Skip to main content

ttf_view/types/
uint24mod.rs

1use crate::util::impl_fmt_with;
2
3#[derive(Copy, Hash)]
4#[derive_const(Clone, PartialEq, Eq, PartialOrd, Ord)]
5#[repr(transparent)]
6pub struct uint24([u8; 3]);
7
8impl uint24 {
9    pub const BITS: u32 = 24;
10    pub const MIN: Self = Self::new(0x000000).unwrap();
11    pub const MAX: Self = Self::new(0xFFFFFF).unwrap();
12
13    pub const fn new(num: u32) -> Option<Self> {
14        if num <= 0xFFFFFF { Some(unsafe { Self::new_unchecked(num) }) } else { None }
15    }
16    pub const unsafe fn new_unchecked(num: u32) -> Self {
17        debug_assert!(num <= 0xFFFFFF);
18        let buf = num.to_be_bytes();
19        Self(*buf.last_chunk::<3>().unwrap())
20    }
21
22    pub const fn from_be_bytes(bytes: [u8; 3]) -> Self {
23        Self(bytes)
24    }
25    pub const fn to_be_bytes(self) -> [u8; 3] {
26        self.0
27    }
28
29    pub const fn get(&self) -> u32 {
30        let mut buf = [0; 4];
31        buf[1..].copy_from_slice(&self.0);
32        u32::from_be_bytes(buf)
33    }
34}
35
36impl_fmt_with! {
37    Debug, Display, Binary, Octal, LowerHex, UpperHex, LowerExp, UpperExp:
38    |this: &uint24, f| this.get().fmt(f)
39}
40
41// TODO: When [u8; 3]'s Default is constified, replace this impl with #[derive_const]
42#[allow(clippy::derivable_impls)]
43const impl Default for uint24 {
44    fn default() -> Self {
45        Self([0; 3])
46    }
47}
48
49const impl PartialEq<u32> for uint24 {
50    fn eq(&self, other: &u32) -> bool {
51        self.get().eq(other)
52    }
53}
54const impl PartialOrd<u32> for uint24 {
55    fn partial_cmp(&self, other: &u32) -> Option<std::cmp::Ordering> {
56        Some(self.get().cmp(other))
57    }
58}
59
60const impl std::str::FromStr for uint24 {
61    type Err = ();
62    fn from_str(s: &str) -> Result<Self, Self::Err> {
63        u32::from_str(s).or(Err(())).and_then(Self::try_from)
64    }
65}
66const impl TryFrom<u32> for uint24 {
67    type Error = ();
68    fn try_from(value: u32) -> Result<Self, Self::Error> {
69        Self::new(value).ok_or(())
70    }
71}
72const impl From<uint24> for u32 {
73    fn from(value: uint24) -> Self {
74        value.get()
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn conv() {
84        assert_eq!(uint24::new(0).unwrap(), 0);
85        assert_eq!(uint24::new(27).unwrap(), 27);
86        assert_eq!(uint24::new(256).unwrap(), 256);
87        assert_eq!(uint24::new(0xFFFFFF).unwrap(), 0xFFFFFF);
88        assert_eq!(uint24::new(0x01000000), None);
89        assert_eq!(uint24::new(0xFFFFFFFF), None);
90    }
91}