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> − 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}