Skip to main content

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