1#[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 pub const MIN: Self = Uint24(0);
14
15 pub const MAX: Self = Uint24(0xffffff);
17
18 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 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 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#[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}