ring/
endian.rs

1use core::num::Wrapping;
2
3/// An `Encoding` of a type `T` can be converted to/from its byte
4/// representation without any byte swapping or other computation.
5///
6/// The `Self: Copy` constraint addresses `clippy::declare_interior_mutable_const`.
7pub trait Encoding<T>: From<T> + Into<T>
8where
9    Self: Copy,
10{
11    const ZERO: Self;
12}
13
14macro_rules! define_endian {
15    ($endian:ident) => {
16        #[derive(Clone, Copy)]
17        #[repr(transparent)]
18        pub struct $endian<T>(T);
19    };
20}
21
22macro_rules! impl_endian {
23    ($endian:ident, $base:ident, $to_endian:ident, $from_endian:ident, $size:expr) => {
24        impl Encoding<$base> for $endian<$base> {
25            const ZERO: Self = Self(0);
26        }
27
28        impl From<[u8; $size]> for $endian<$base> {
29            #[inline]
30            fn from(bytes: [u8; $size]) -> Self {
31                Self($base::from_ne_bytes(bytes))
32            }
33        }
34
35        impl From<$endian<$base>> for [u8; $size] {
36            #[inline]
37            fn from(encoded: $endian<$base>) -> Self {
38                $base::to_ne_bytes(encoded.0)
39            }
40        }
41
42        impl From<$base> for $endian<$base> {
43            #[inline]
44            fn from(value: $base) -> Self {
45                Self($base::$to_endian(value))
46            }
47        }
48
49        impl From<Wrapping<$base>> for $endian<$base> {
50            #[inline]
51            fn from(Wrapping(value): Wrapping<$base>) -> Self {
52                Self($base::$to_endian(value))
53            }
54        }
55
56        impl From<$endian<$base>> for $base {
57            #[inline]
58            fn from($endian(value): $endian<$base>) -> Self {
59                $base::$from_endian(value)
60            }
61        }
62    };
63}
64
65define_endian!(BigEndian);
66impl_endian!(BigEndian, u32, to_be, from_be, 4);
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn test_big_endian() {
74        let x = BigEndian::from(1u32);
75        assert_eq!(u32::from(x), 1);
76    }
77}