font_types/
int24.rs

1/// 24-bit unsigned integer.
2#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
3#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4#[cfg_attr(feature = "bytemuck", derive(bytemuck::AnyBitPattern))]
5#[repr(transparent)]
6pub struct Int24(i32);
7
8impl Int24 {
9    /// The smallest value that can be represented by this integer type.
10    pub const MIN: Self = Int24(-0x80_00_00);
11
12    /// The largest value that can be represented by this integer type.
13    pub const MAX: Self = Int24(0x7F_FF_FF);
14
15    /// Create from a i32. Saturates on overflow.
16    pub const fn new(raw: i32) -> Int24 {
17        let overflow = raw > Self::MAX.0;
18        let underflow = raw < Self::MIN.0;
19        let raw = raw * !(overflow || underflow) as i32
20            + Self::MAX.0 * overflow as i32
21            + Self::MIN.0 * underflow as i32;
22        Int24(raw)
23    }
24
25    /// Create from a i32, returning `None` if the value overflows.
26    pub const fn checked_new(raw: i32) -> Option<Int24> {
27        if raw > Self::MAX.0 || raw < Self::MIN.0 {
28            None
29        } else {
30            Some(Int24(raw))
31        }
32    }
33
34    /// Returns this value as an unsigned 32-bit integer.
35    pub const fn to_i32(self) -> i32 {
36        self.0
37    }
38
39    pub const fn to_be_bytes(self) -> [u8; 3] {
40        let bytes = self.0.to_be_bytes();
41        [bytes[1], bytes[2], bytes[3]]
42    }
43
44    pub const fn from_be_bytes(bytes: [u8; 3]) -> Self {
45        let extra_byte = ((bytes[0] & 0b10000000) >> 7) * 0b11111111;
46        let extra_byte = (extra_byte as i32) << 24;
47        Int24::new(
48            extra_byte | ((bytes[0] as i32) << 16) | ((bytes[1] as i32) << 8) | bytes[2] as i32,
49        )
50    }
51}
52
53impl From<Int24> for i32 {
54    fn from(src: Int24) -> i32 {
55        src.0
56    }
57}
58
59impl std::fmt::Display for Int24 {
60    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
61        self.0.fmt(f)
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn constructor() {
71        assert_eq!(Int24::MAX, Int24::new(i32::MAX));
72        assert_eq!(Int24::MIN, Int24::new(i32::MIN));
73        assert_eq!(-10, Int24::new(-10).to_i32());
74        assert_eq!(10, Int24::new(10).to_i32());
75    }
76
77    #[test]
78    fn to_be_bytes() {
79        assert_eq!(
80            Int24::new(0).to_be_bytes(),
81            [0b00000000, 0b00000000, 0b00000000]
82        );
83
84        assert_eq!(
85            Int24::new(123_456).to_be_bytes(),
86            [0b00000001, 0b11100010, 0b01000000]
87        );
88        assert_eq!(
89            Int24::new(-123_456).to_be_bytes(),
90            [0b11111110, 0b00011101, 0b11000000]
91        );
92
93        assert_eq!(
94            Int24::new(0x7F_FF_FF).to_be_bytes(),
95            [0b01111111, 0b11111111, 0b11111111]
96        );
97        assert_eq!(
98            Int24::new(-0x80_00_00).to_be_bytes(),
99            [0b10000000, 0b00000000, 0b00000000]
100        );
101    }
102
103    #[test]
104    fn from_be_bytes() {
105        assert_eq!(
106            Int24::from_be_bytes([0b00000000, 0b00000000, 0b00000000]),
107            Int24::new(0)
108        );
109
110        assert_eq!(
111            Int24::from_be_bytes([0b00000001, 0b11100010, 0b01000000]),
112            Int24::new(123_456)
113        );
114        assert_eq!(
115            Int24::from_be_bytes([0b11111110, 0b00011101, 0b11000000]),
116            Int24::new(-123_456)
117        );
118
119        assert_eq!(
120            Int24::from_be_bytes([0b01111111, 0b11111111, 0b11111111]),
121            Int24::new(0x7F_FF_FF)
122        );
123        assert_eq!(
124            Int24::from_be_bytes([0b10000000, 0b00000000, 0b00000000]),
125            Int24::new(-0x80_00_00)
126        );
127    }
128
129    #[test]
130    fn round_trip() {
131        for v in Int24::MIN.to_i32()..=Int24::MAX.to_i32() {
132            let int = Int24::new(v);
133            let bytes = int.to_be_bytes();
134            let int_prime = Int24::from_be_bytes(bytes);
135            assert_eq!(int_prime, int);
136        }
137    }
138}