Skip to main content

ttf_view/types/
uint24mod.rs

1use crate::util::impl_fmt_with;
2
3/// The 24-bit unsigned integer type stored in big-endian byte order.
4#[derive(Copy, Hash)]
5#[derive_const(Clone, PartialEq, Eq, PartialOrd, Ord)]
6#[repr(transparent)]
7pub struct uint24([u8; 3]);
8
9impl uint24 {
10    /// The size of this integer type in bits.
11    ///
12    /// # Examples
13    ///
14    /// ```
15    /// # use ttf_view::types::uint24;
16    /// assert_eq!(uint24::BITS, 24);
17    /// ```
18    pub const BITS: u32 = 24;
19    /// The smallest value that can be represented by this integer type.
20    ///
21    /// # Examples
22    ///
23    /// ```
24    /// # use ttf_view::types::uint24;
25    /// assert_eq!(uint24::MIN, 0);
26    /// ```
27    pub const MIN: Self = Self::new(0x000000).unwrap();
28    /// The largest value that can be represented by this integer type (2<sup>24</sup> &minus; 1).
29    ///
30    /// # Examples
31    ///
32    /// ```
33    /// # use ttf_view::types::uint24;
34    /// assert_eq!(uint24::MAX, 16_777_215);
35    /// ```
36    pub const MAX: Self = Self::new(0xFFFFFF).unwrap();
37
38    /// Creates a big-endian [`uint24`] from [`u32`].
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// use ttf_view::types::uint24;
44    ///
45    /// assert_eq!(uint24::new(1234).unwrap(), 1234);
46    /// assert_eq!(uint24::new(15_000_000).unwrap(), 15_000_000);
47    /// assert_eq!(uint24::new(0xFFFFFF).unwrap(), 0xFFFFFF);
48    /// assert_eq!(uint24::new(17_000_000), None);
49    /// assert_eq!(uint24::new(3_999_000_000), None);
50    /// ```
51    pub const fn new(num: u32) -> Option<Self> {
52        if num <= 0xFFFFFF { Some(unsafe { Self::new_unchecked(num) }) } else { None }
53    }
54    /// Creates a big-endian [`uint24`] from [`u32`] without checks.
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use ttf_view::types::uint24;
60    ///
61    /// assert_eq!(unsafe { uint24::new_unchecked(1234).get() }, 1234);
62    /// assert_eq!(unsafe { uint24::new_unchecked(15_000_000).get() }, 15_000_000);
63    /// ```
64    pub const unsafe fn new_unchecked(num: u32) -> Self {
65        debug_assert!(num <= 0xFFFFFF);
66        let buf = num.to_be_bytes();
67        Self(*buf.last_chunk::<3>().unwrap())
68    }
69
70    /// Creates a big-endian [`uint24`] from big-endian bytes.
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use ttf_view::types::uint24;
76    ///
77    /// assert_eq!(uint24::from_be_bytes([0x00, 0x00, 0x07]), 7);
78    /// assert_eq!(uint24::from_be_bytes([0x12, 0x34, 0x56]), 0x00123456);
79    /// ```
80    pub const fn from_be_bytes(bytes: [u8; 3]) -> Self {
81        Self(bytes)
82    }
83    /// Gets this [`uint24`]'s big-endian bytes.
84    ///
85    /// # Examples
86    ///
87    /// ```
88    /// use ttf_view::types::uint24;
89    ///
90    /// assert_eq!(uint24::new(7).unwrap().to_be_bytes(), [0x00, 0x00, 0x07]);
91    /// assert_eq!(uint24::new(0x00123456).unwrap().to_be_bytes(), [0x12, 0x34, 0x56]);
92    /// ```
93    pub const fn to_be_bytes(self) -> [u8; 3] {
94        self.0
95    }
96
97    /// Gets the value of this [`uint24`] as [`u32`].
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use ttf_view::types::uint24;
103    ///
104    /// assert_eq!(uint24::new(1234).unwrap(), 1234);
105    /// assert_eq!(uint24::new(15_000_000).unwrap(), 15_000_000);
106    /// ```
107    pub const fn get(&self) -> u32 {
108        let mut buf = [0; 4];
109        buf[1..].copy_from_slice(&self.0);
110        u32::from_be_bytes(buf)
111    }
112}
113
114impl_fmt_with! {
115    Debug, Display, Binary, Octal, LowerHex, UpperHex, LowerExp, UpperExp:
116    |this: &uint24| this.get()
117}
118
119// TODO: When [u8; 3]'s Default is constified, replace this impl with #[derive_const]
120#[allow(clippy::derivable_impls)]
121const impl Default for uint24 {
122    fn default() -> Self {
123        Self([0; 3])
124    }
125}
126
127const impl PartialEq<u32> for uint24 {
128    fn eq(&self, other: &u32) -> bool {
129        self.get().eq(other)
130    }
131}
132const impl PartialOrd<u32> for uint24 {
133    fn partial_cmp(&self, other: &u32) -> Option<std::cmp::Ordering> {
134        Some(self.get().cmp(other))
135    }
136}
137
138const impl std::str::FromStr for uint24 {
139    type Err = ();
140    fn from_str(s: &str) -> Result<Self, Self::Err> {
141        u32::from_str(s).or(Err(())).and_then(Self::try_from)
142    }
143}
144const impl TryFrom<u32> for uint24 {
145    type Error = ();
146    fn try_from(value: u32) -> Result<Self, Self::Error> {
147        Self::new(value).ok_or(())
148    }
149}
150const impl From<uint24> for u32 {
151    fn from(value: uint24) -> Self {
152        value.get()
153    }
154}