1use std::fmt::Debug;
2
3#[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 #[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]]); be_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(); dbg!(n);
87}