mca_parser/
bigendian.rs

1use std::fmt::Debug;
2
3/// Represents a number of `N` bytes that is stored in BigEndian format
4#[repr(transparent)]
5#[derive(Clone, Copy, Eq, PartialEq)]
6pub(crate) struct BigEndian<const N: usize> {
7    inner: [u8; N],
8}
9
10impl<const N: usize> From<[u8; N]> for BigEndian<N> {
11    fn from(value: [u8; N]) -> Self {
12        Self { inner: value }
13    }
14}
15
16macro_rules! be_impl {
17    ($N: literal => $num_type: ty: $var: ident => $e: expr) => {
18        impl From<BigEndian<$N>> for $num_type {
19            fn from(be: BigEndian<$N>) -> Self {
20                let $var = be.inner;
21                Self::from_be_bytes($e)
22            }
23        }
24
25        impl Debug for BigEndian<$N> {
26            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27                write!(f, "{}", <$num_type>::from(*self))
28            }
29        }
30    };
31    ($N: literal => $num_type: ty) => {
32        be_impl!($N => $num_type: a => a);
33    };
34}
35
36impl From<u32> for BigEndian<4> {
37    fn from(value: u32) -> Self {
38        Self::from(value.to_be_bytes())
39    }
40}
41
42impl<const N: usize> BigEndian<N> {
43    // intended for use in testing, if we ever need this fn, we can remove the `#[cfg(test)]`
44    // attribute
45    #[cfg(test)]
46    pub const fn into_bytes(self) -> [u8; N] {
47        self.inner
48    }
49
50    pub const fn as_u32(&self) -> u32 {
51        if N > 4 {
52            panic!();
53        }
54
55        match N {
56            4 => u32::from_be_bytes([self.inner[0], self.inner[1], self.inner[2], self.inner[3]]),
57            3 => u32::from_be_bytes([0, self.inner[0], self.inner[1], self.inner[2]]),
58            2 => u32::from_be_bytes([0, 0, self.inner[0], self.inner[1]]),
59            1 => u32::from_be_bytes([0, 0, 0, self.inner[0]]),
60            _ => unreachable!(),
61        }
62    }
63}
64
65be_impl!(3 => u32: a => [0, a[0], a[1], a[2]]); // if we have only three bytes, make the top one zero
66be_impl!(4 => u32);
67
68#[test]
69fn test() {
70    let be = BigEndian::from([0, 0, 0, 1]);
71    assert_eq!(be.as_u32(), 1);
72    assert_eq!(u32::from(be), 1);
73
74    let be = BigEndian::from([0, 0, 1]);
75    assert_eq!(be.as_u32(), 1);
76    assert_eq!(u32::from(be), 1);
77}
78
79#[test]
80#[should_panic]
81fn test_invalid_n() {
82    let be = BigEndian::from([0, 0, 0, 0, 1]);
83    let n = be.as_u32(); // Should Panic
84
85    // if it doesn't, please tell me the value
86    dbg!(n);
87}