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);