font_types/
int24.rs
1#[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 pub const MIN: Self = Int24(-0x80_00_00);
11
12 pub const MAX: Self = Int24(0x7F_FF_FF);
14
15 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 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 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}