1pub trait Encoding<T>: From<T> + Into<T>
11where
12 Self: Copy,
13{
14 const ZERO: Self;
15}
16
17use core::mem::size_of_val;
18
19pub fn as_byte_slice<E: Encoding<T>, T>(x: &[E]) -> &[u8] {
20 unsafe { core::slice::from_raw_parts(x.as_ptr().cast::<u8>(), size_of_val(x)) }
21}
22
23pub trait ArrayEncoding<T> {
26 fn as_byte_array(&self) -> &T;
27}
28
29pub trait FromArray<const N: usize, T>
32where
33 Self: Sized,
34{
35 fn from_array(a: &[T; N]) -> [Self; N];
36}
37
38macro_rules! define_endian {
39 ($endian:ident) => {
40 #[derive(Copy, Clone)]
41 #[repr(transparent)]
42 pub struct $endian<T>(T);
43 };
44}
45
46macro_rules! impl_array_encoding {
47 ($endian:ident, $base:ident, $elems:expr) => {
50 impl ArrayEncoding<[u8; $elems * core::mem::size_of::<$base>()]>
51 for [$endian<$base>; $elems]
52 {
53 fn as_byte_array(&self) -> &[u8; $elems * core::mem::size_of::<$base>()] {
54 as_byte_slice(self).try_into().unwrap()
55 }
56 }
57 };
58}
59
60macro_rules! impl_endian {
61 ($endian:ident, $base:ident, $to_endian:ident, $from_endian:ident, $size:expr) => {
62 impl Encoding<$base> for $endian<$base> {
63 const ZERO: Self = Self(0);
64 }
65
66 impl From<$base> for $endian<$base> {
67 #[inline]
68 fn from(value: $base) -> Self {
69 Self($base::$to_endian(value))
70 }
71 }
72
73 impl From<$endian<$base>> for $base {
74 #[inline]
75 fn from($endian(value): $endian<$base>) -> Self {
76 $base::$from_endian(value)
77 }
78 }
79
80 impl<const N: usize> FromArray<N, $base> for $endian<$base> {
81 fn from_array(value: &[$base; N]) -> [Self; N] {
82 let mut result: [$endian<$base>; N] = [$endian::ZERO; N];
83 for i in 0..N {
84 result[i] = $endian::from(value[i]);
85 }
86 return result;
87 }
88 }
89
90 impl_array_encoding!($endian, $base, 1);
91 impl_array_encoding!($endian, $base, 2);
92 impl_array_encoding!($endian, $base, 3);
93 impl_array_encoding!($endian, $base, 4);
94 impl_array_encoding!($endian, $base, 8);
95 };
96}
97
98define_endian!(BigEndian);
99define_endian!(LittleEndian);
100impl_endian!(BigEndian, u32, to_be, from_be, 4);
101impl_endian!(BigEndian, u64, to_be, from_be, 8);
102impl_endian!(LittleEndian, u32, to_le, from_le, 4);
103impl_endian!(LittleEndian, u64, to_le, from_le, 8);
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_big_endian() {
111 let x = BigEndian::from(1u32);
112 let x2 = x;
113 assert_eq!(u32::from(x), 1);
114 assert_eq!(u32::from(x2), 1);
115 }
116
117 #[test]
118 fn test_endian_from_array() {
119 let be: [BigEndian<u32>; 2] =
120 BigEndian::<u32>::from_array(&[0x_AABB_CCDD_u32, 0x_2233_4455_u32]);
121 let le: [LittleEndian<u32>; 2] =
122 LittleEndian::<u32>::from_array(&[0x_DDCC_BBAA_u32, 0x_5544_3322_u32]);
123 assert_eq!(be.as_byte_array(), le.as_byte_array());
124
125 let be: [BigEndian<u64>; 2] =
126 BigEndian::<u64>::from_array(&[0x_AABB_CCDD_EEFF_0011_u64, 0x_2233_4455_6677_8899_u64]);
127 let le: [LittleEndian<u64>; 2] = LittleEndian::<u64>::from_array(&[
128 0x_1100_FFEE_DDCC_BBAA_u64,
129 0x_9988_7766_5544_3322_u64,
130 ]);
131 assert_eq!(be.as_byte_array(), le.as_byte_array());
132 }
133}