font_types/
uint24.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 Uint24(u32);
7
8impl Uint24 {
9    /// The smallest value that can be represented by this integer type.
10    pub const MIN: Self = Uint24(0);
11
12    /// The largest value that can be represented by this integer type.
13    pub const MAX: Self = Uint24(0xffffff);
14
15    /// Create from a u32. Saturates on overflow.
16    pub const fn new(raw: u32) -> Uint24 {
17        let overflow = raw > Self::MAX.0;
18        let raw = raw * !overflow as u32 + Self::MAX.0 * overflow as u32;
19        Uint24(raw)
20    }
21
22    /// Create from a u32, returning `None` if the value overflows.
23    pub const fn checked_new(raw: u32) -> Option<Uint24> {
24        if raw > Self::MAX.0 {
25            None
26        } else {
27            Some(Uint24(raw))
28        }
29    }
30
31    /// Returns this value as an unsigned 32-bit integer.
32    pub const fn to_u32(self) -> u32 {
33        self.0
34    }
35
36    pub const fn to_be_bytes(self) -> [u8; 3] {
37        let bytes = self.0.to_be_bytes();
38        [bytes[1], bytes[2], bytes[3]]
39    }
40
41    pub const fn from_be_bytes(bytes: [u8; 3]) -> Self {
42        Uint24::new(((bytes[0] as u32) << 16) | ((bytes[1] as u32) << 8) | bytes[2] as u32)
43    }
44}
45
46impl From<Uint24> for u32 {
47    fn from(src: Uint24) -> u32 {
48        src.0
49    }
50}
51
52impl From<Uint24> for usize {
53    fn from(src: Uint24) -> usize {
54        src.0 as usize
55    }
56}
57
58/// Indicates an error converting an integer value into a Uint24 due to overflow.
59#[derive(Debug)]
60pub struct TryFromUint24Error;
61
62impl std::fmt::Display for TryFromUint24Error {
63    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
64        write!(f, "failed to convert usize value into Uint24.")
65    }
66}
67
68#[cfg(feature = "std")]
69impl std::error::Error for TryFromUint24Error {}
70
71impl TryFrom<usize> for Uint24 {
72    type Error = TryFromUint24Error;
73
74    fn try_from(value: usize) -> Result<Self, Self::Error> {
75        let u32_value = u32::try_from(value).map_err(|_| TryFromUint24Error)?;
76        Uint24::checked_new(u32_value).ok_or(TryFromUint24Error)
77    }
78}
79
80impl std::fmt::Display for Uint24 {
81    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
82        self.0.fmt(f)
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn constructor() {
92        assert_eq!(Uint24::MAX, Uint24::new(u32::MAX));
93        assert!(Uint24::checked_new(u32::MAX).is_none())
94    }
95
96    #[test]
97    fn be_bytes() {
98        let bytes = [0xff, 0b10101010, 0b11001100];
99        let val = Uint24::from_be_bytes(bytes);
100        assert_eq!(val.to_be_bytes(), bytes);
101    }
102}