1 use core::borrow::{Borrow, BorrowMut};
2 use core::cmp::{Eq, Ord, PartialEq, PartialOrd};
3 use core::fmt::Debug;
4 use core::hash::Hash;
5 
6 pub trait NumBytes:
7     Debug
8     + AsRef<[u8]>
9     + AsMut<[u8]>
10     + PartialEq
11     + Eq
12     + PartialOrd
13     + Ord
14     + Hash
15     + Borrow<[u8]>
16     + BorrowMut<[u8]>
17 {
18 }
19 
20 impl<T> NumBytes for T where
21     T: Debug
22         + AsRef<[u8]>
23         + AsMut<[u8]>
24         + PartialEq
25         + Eq
26         + PartialOrd
27         + Ord
28         + Hash
29         + Borrow<[u8]>
30         + BorrowMut<[u8]>
31         + ?Sized
32 {
33 }
34 
35 pub trait ToBytes {
36     type Bytes: NumBytes;
37 
38     /// Return the memory representation of this number as a byte array in big-endian byte order.
39     ///
40     /// # Examples
41     ///
42     /// ```
43     /// use num_traits::ToBytes;
44     ///
45     /// let bytes = ToBytes::to_be_bytes(&0x12345678u32);
46     /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
47     /// ```
to_be_bytes(&self) -> Self::Bytes48     fn to_be_bytes(&self) -> Self::Bytes;
49 
50     /// Return the memory representation of this number as a byte array in little-endian byte order.
51     ///
52     /// # Examples
53     ///
54     /// ```
55     /// use num_traits::ToBytes;
56     ///
57     /// let bytes = ToBytes::to_le_bytes(&0x12345678u32);
58     /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]);
59     /// ```
to_le_bytes(&self) -> Self::Bytes60     fn to_le_bytes(&self) -> Self::Bytes;
61 
62     /// Return the memory representation of this number as a byte array in native byte order.
63     ///
64     /// As the target platform's native endianness is used,
65     /// portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead.
66     ///
67     /// [`to_be_bytes`]: #method.to_be_bytes
68     /// [`to_le_bytes`]: #method.to_le_bytes
69     ///
70     /// # Examples
71     ///
72     /// ```
73     /// use num_traits::ToBytes;
74     ///
75     /// #[cfg(target_endian = "big")]
76     /// let expected = [0x12, 0x34, 0x56, 0x78];
77     ///
78     /// #[cfg(target_endian = "little")]
79     /// let expected = [0x78, 0x56, 0x34, 0x12];
80     ///
81     /// let bytes = ToBytes::to_ne_bytes(&0x12345678u32);
82     /// assert_eq!(bytes, expected)
83     /// ```
to_ne_bytes(&self) -> Self::Bytes84     fn to_ne_bytes(&self) -> Self::Bytes {
85         #[cfg(target_endian = "big")]
86         let bytes = self.to_be_bytes();
87         #[cfg(target_endian = "little")]
88         let bytes = self.to_le_bytes();
89         bytes
90     }
91 }
92 
93 pub trait FromBytes: Sized {
94     type Bytes: NumBytes + ?Sized;
95 
96     /// Create a number from its representation as a byte array in big endian.
97     ///
98     /// # Examples
99     ///
100     /// ```
101     /// use num_traits::FromBytes;
102     ///
103     /// let value: u32 = FromBytes::from_be_bytes(&[0x12, 0x34, 0x56, 0x78]);
104     /// assert_eq!(value, 0x12345678);
105     /// ```
from_be_bytes(bytes: &Self::Bytes) -> Self106     fn from_be_bytes(bytes: &Self::Bytes) -> Self;
107 
108     /// Create a number from its representation as a byte array in little endian.
109     ///
110     /// # Examples
111     ///
112     /// ```
113     /// use num_traits::FromBytes;
114     ///
115     /// let value: u32 = FromBytes::from_le_bytes(&[0x78, 0x56, 0x34, 0x12]);
116     /// assert_eq!(value, 0x12345678);
117     /// ```
from_le_bytes(bytes: &Self::Bytes) -> Self118     fn from_le_bytes(bytes: &Self::Bytes) -> Self;
119 
120     /// Create a number from its memory representation as a byte array in native endianness.
121     ///
122     /// As the target platform's native endianness is used,
123     /// portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead.
124     ///
125     /// [`from_be_bytes`]: #method.from_be_bytes
126     /// [`from_le_bytes`]: #method.from_le_bytes
127     ///
128     /// # Examples
129     ///
130     /// ```
131     /// use num_traits::FromBytes;
132     ///
133     /// #[cfg(target_endian = "big")]
134     /// let bytes = [0x12, 0x34, 0x56, 0x78];
135     ///
136     /// #[cfg(target_endian = "little")]
137     /// let bytes = [0x78, 0x56, 0x34, 0x12];
138     ///
139     /// let value: u32 = FromBytes::from_ne_bytes(&bytes);
140     /// assert_eq!(value, 0x12345678)
141     /// ```
from_ne_bytes(bytes: &Self::Bytes) -> Self142     fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
143         #[cfg(target_endian = "big")]
144         let this = Self::from_be_bytes(bytes);
145         #[cfg(target_endian = "little")]
146         let this = Self::from_le_bytes(bytes);
147         this
148     }
149 }
150 
151 macro_rules! float_to_from_bytes_impl {
152     ($T:ty, $L:expr) => {
153         impl ToBytes for $T {
154             type Bytes = [u8; $L];
155 
156             #[inline]
157             fn to_be_bytes(&self) -> Self::Bytes {
158                 <$T>::to_be_bytes(*self)
159             }
160 
161             #[inline]
162             fn to_le_bytes(&self) -> Self::Bytes {
163                 <$T>::to_le_bytes(*self)
164             }
165 
166             #[inline]
167             fn to_ne_bytes(&self) -> Self::Bytes {
168                 <$T>::to_ne_bytes(*self)
169             }
170         }
171 
172         impl FromBytes for $T {
173             type Bytes = [u8; $L];
174 
175             #[inline]
176             fn from_be_bytes(bytes: &Self::Bytes) -> Self {
177                 <$T>::from_be_bytes(*bytes)
178             }
179 
180             #[inline]
181             fn from_le_bytes(bytes: &Self::Bytes) -> Self {
182                 <$T>::from_le_bytes(*bytes)
183             }
184 
185             #[inline]
186             fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
187                 <$T>::from_ne_bytes(*bytes)
188             }
189         }
190     };
191 }
192 
193 macro_rules! int_to_from_bytes_impl {
194     ($T:ty, $L:expr) => {
195         impl ToBytes for $T {
196             type Bytes = [u8; $L];
197 
198             #[inline]
199             fn to_be_bytes(&self) -> Self::Bytes {
200                 <$T>::to_be_bytes(*self)
201             }
202 
203             #[inline]
204             fn to_le_bytes(&self) -> Self::Bytes {
205                 <$T>::to_le_bytes(*self)
206             }
207 
208             #[inline]
209             fn to_ne_bytes(&self) -> Self::Bytes {
210                 <$T>::to_ne_bytes(*self)
211             }
212         }
213 
214         impl FromBytes for $T {
215             type Bytes = [u8; $L];
216 
217             #[inline]
218             fn from_be_bytes(bytes: &Self::Bytes) -> Self {
219                 <$T>::from_be_bytes(*bytes)
220             }
221 
222             #[inline]
223             fn from_le_bytes(bytes: &Self::Bytes) -> Self {
224                 <$T>::from_le_bytes(*bytes)
225             }
226 
227             #[inline]
228             fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
229                 <$T>::from_ne_bytes(*bytes)
230             }
231         }
232     };
233 }
234 
235 int_to_from_bytes_impl!(u8, 1);
236 int_to_from_bytes_impl!(u16, 2);
237 int_to_from_bytes_impl!(u32, 4);
238 int_to_from_bytes_impl!(u64, 8);
239 int_to_from_bytes_impl!(u128, 16);
240 #[cfg(target_pointer_width = "64")]
241 int_to_from_bytes_impl!(usize, 8);
242 #[cfg(target_pointer_width = "32")]
243 int_to_from_bytes_impl!(usize, 4);
244 
245 int_to_from_bytes_impl!(i8, 1);
246 int_to_from_bytes_impl!(i16, 2);
247 int_to_from_bytes_impl!(i32, 4);
248 int_to_from_bytes_impl!(i64, 8);
249 int_to_from_bytes_impl!(i128, 16);
250 #[cfg(target_pointer_width = "64")]
251 int_to_from_bytes_impl!(isize, 8);
252 #[cfg(target_pointer_width = "32")]
253 int_to_from_bytes_impl!(isize, 4);
254 
255 float_to_from_bytes_impl!(f32, 4);
256 float_to_from_bytes_impl!(f64, 8);
257 
258 #[cfg(test)]
259 mod tests {
260     use super::*;
261 
262     macro_rules! check_to_from_bytes {
263         ($( $ty:ty )+) => {$({
264             let n = 1;
265             let be = <$ty as ToBytes>::to_be_bytes(&n);
266             let le = <$ty as ToBytes>::to_le_bytes(&n);
267             let ne = <$ty as ToBytes>::to_ne_bytes(&n);
268 
269             assert_eq!(*be.last().unwrap(), 1);
270             assert_eq!(*le.first().unwrap(), 1);
271             if cfg!(target_endian = "big") {
272                 assert_eq!(*ne.last().unwrap(), 1);
273             } else {
274                 assert_eq!(*ne.first().unwrap(), 1);
275             }
276 
277             assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n);
278             assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n);
279             if cfg!(target_endian = "big") {
280                 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n);
281             } else {
282                 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n);
283             }
284         })+}
285     }
286 
287     #[test]
convert_between_int_and_bytes()288     fn convert_between_int_and_bytes() {
289         check_to_from_bytes!(u8 u16 u32 u64 u128 usize);
290         check_to_from_bytes!(i8 i16 i32 i64 i128 isize);
291     }
292 
293     #[test]
convert_between_float_and_bytes()294     fn convert_between_float_and_bytes() {
295         macro_rules! check_to_from_bytes {
296             ($( $ty:ty )+) => {$(
297                 let n: $ty = 3.14;
298 
299                 let be = <$ty as ToBytes>::to_be_bytes(&n);
300                 let le = <$ty as ToBytes>::to_le_bytes(&n);
301                 let ne = <$ty as ToBytes>::to_ne_bytes(&n);
302 
303                 assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n);
304                 assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n);
305                 if cfg!(target_endian = "big") {
306                     assert_eq!(ne, be);
307                     assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n);
308                 } else {
309                     assert_eq!(ne, le);
310                     assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n);
311                 }
312             )+}
313         }
314 
315         check_to_from_bytes!(f32 f64);
316     }
317 }
318