number_bytes/
lib.rs

1use core::array::TryFromSliceError;
2
3#[cfg(feature = "endianness")]
4pub mod endianness;
5
6#[cfg(test)]
7pub mod tests;
8
9pub type FromBytesError = TryFromSliceError;
10pub type FromBytesResult<T> = Result<T, FromBytesError>;
11
12pub trait NumberBytes: Sized {
13    /// How many bytes a value of this type consists of.
14    /// 
15    /// A single byte explicitly refers to 8 bits and the builtin [`u8`] type.
16    const BYTES: usize;
17
18    /// Returns the memory representation of this integer as a byte array in native byte order.
19    /// 
20    /// Type-generic wrapper around [`to_ne_bytes`] for inbuilt number types. See [`usize::to_ne_bytes`].
21    /// 
22    /// Size of the output vector shall always be the value of [`Self::BYTES`].
23    fn to_ne_bytes(self) -> Vec<u8>;
24
25    /// Creates a native endian value from its memory representation as a byte array in native endianness.
26    /// 
27    /// Type-generic wrapper around [`from_ne_bytes`] for inbuilt number types. See [`usize::from_ne_bytes`].
28    /// 
29    /// Returns [`FromBytesError`] if the size of the given byte-slice is incorrect.
30    fn from_ne_bytes(bytes: &[u8]) -> FromBytesResult<Self>;
31
32    /// Returns the memory representation of this integer as a byte array in big-endian (network) byte order.
33    /// 
34    /// Type-generic wrapper around [`to_be_bytes`] for inbuilt number types. See [`usize::to_be_bytes`].
35    /// 
36    /// Size of the output vector shall always be the value of [`Self::BYTES`].
37    fn to_be_bytes(self) -> Vec<u8>;
38
39    /// Creates a native endian integer value from its representation as a byte array in big endian.
40    /// 
41    /// Type-generic wrapper around [`from_be_bytes`] for inbuilt number types. See [`usize::from_be_bytes`].
42    /// 
43    /// Returns [`FromBytesError`] if the size of the given byte-slice is incorrect.
44    fn from_be_bytes(bytes: &[u8]) -> FromBytesResult<Self>;
45
46    /// Returns the memory representation of this integer as a byte array in little-endian byte order.
47    /// 
48    /// Type-generic wrapper around [`to_le_bytes`] for inbuilt number types. See [`usize::to_le_bytes`].
49    /// 
50    /// Size of the output vector shall always be the value of [`Self::BYTES`].
51    fn to_le_bytes(self) -> Vec<u8>;
52
53    /// Creates a native endian integer value from its representation as a byte array in little endian.
54    /// 
55    /// Type-generic wrapper around [`from_le_bytes`] for inbuilt number types. See [`usize::from_le_bytes`].
56    /// 
57    /// Returns [`FromBytesError`] if the size of the given byte-slice is incorrect.
58    fn from_le_bytes(bytes: &[u8]) -> FromBytesResult<Self>;
59}
60
61macro_rules! impl_number_bytes {
62    ($number_type:ty) => {
63        impl_number_bytes!(
64            $number_type,
65            <$number_type>::BITS as usize / 8
66        );
67    };
68
69    ($number_type:ty, $bytes:expr) => {
70        impl NumberBytes for $number_type {
71            const BYTES: usize = $bytes;
72
73            fn from_ne_bytes(bytes: &[u8]) -> FromBytesResult<Self> {
74                wrap_from_bytes(bytes, Self::from_ne_bytes)
75            }
76
77            fn to_ne_bytes(self) -> Vec<u8> {
78                wrap_to_bytes(self, Self::to_ne_bytes)
79            }
80
81            fn from_be_bytes(bytes: &[u8]) -> FromBytesResult<Self> {
82                wrap_from_bytes(bytes, Self::from_be_bytes)
83            }
84
85            fn to_be_bytes(self) -> Vec<u8> {
86                wrap_to_bytes(self, Self::to_be_bytes)
87            }
88
89            fn from_le_bytes(bytes: &[u8]) -> FromBytesResult<Self> {
90                wrap_from_bytes(bytes, Self::from_le_bytes)
91            }
92
93            fn to_le_bytes(self) -> Vec<u8> {
94                wrap_to_bytes(self, Self::to_le_bytes)
95            }
96        }
97    };
98}
99
100#[inline(always)]
101fn wrap_from_bytes<T, const BYTES: usize>(bytes: &[u8], from_bytes_fn: fn([u8; BYTES]) -> T) -> FromBytesResult<T> {
102    let bytes_array = bytes.try_into()?;
103    Ok(from_bytes_fn(bytes_array))
104}
105
106#[inline(always)]
107fn wrap_to_bytes<T, const BYTES: usize>(instance: T, to_bytes_fn: fn(T) -> [u8; BYTES]) -> Vec<u8> {
108    to_bytes_fn(instance).to_vec()
109}
110
111impl_number_bytes!(u8);
112impl_number_bytes!(u16);
113impl_number_bytes!(u32);
114impl_number_bytes!(u64);
115impl_number_bytes!(u128);
116impl_number_bytes!(usize);
117
118impl_number_bytes!(i8);
119impl_number_bytes!(i16);
120impl_number_bytes!(i32);
121impl_number_bytes!(i64);
122impl_number_bytes!(i128);
123impl_number_bytes!(isize);
124
125// Floating point types don't provide the BITS constant, so we must define the byte count manually.
126impl_number_bytes!(f32, 32 / 8);
127impl_number_bytes!(f64, 64 / 8);