• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #[cfg(not(has_int_to_from_bytes))]
6 use core::mem::transmute;
7 
8 pub trait NumBytes:
9     Debug
10     + AsRef<[u8]>
11     + AsMut<[u8]>
12     + PartialEq
13     + Eq
14     + PartialOrd
15     + Ord
16     + Hash
17     + Borrow<[u8]>
18     + BorrowMut<[u8]>
19 {
20 }
21 
22 impl<T> NumBytes for T where
23     T: Debug
24         + AsRef<[u8]>
25         + AsMut<[u8]>
26         + PartialEq
27         + Eq
28         + PartialOrd
29         + Ord
30         + Hash
31         + Borrow<[u8]>
32         + BorrowMut<[u8]>
33         + ?Sized
34 {
35 }
36 
37 pub trait ToBytes {
38     type Bytes: NumBytes;
39 
40     /// Return the memory representation of this number as a byte array in big-endian byte order.
41     ///
42     /// # Examples
43     ///
44     /// ```
45     /// use num_traits::ToBytes;
46     ///
47     /// let bytes = ToBytes::to_be_bytes(&0x12345678u32);
48     /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
49     /// ```
to_be_bytes(&self) -> Self::Bytes50     fn to_be_bytes(&self) -> Self::Bytes;
51 
52     /// Return the memory representation of this number as a byte array in little-endian byte order.
53     ///
54     /// # Examples
55     ///
56     /// ```
57     /// use num_traits::ToBytes;
58     ///
59     /// let bytes = ToBytes::to_le_bytes(&0x12345678u32);
60     /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]);
61     /// ```
to_le_bytes(&self) -> Self::Bytes62     fn to_le_bytes(&self) -> Self::Bytes;
63 
64     /// Return the memory representation of this number as a byte array in native byte order.
65     ///
66     /// As the target platform's native endianness is used,
67     /// portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead.
68     ///
69     /// [`to_be_bytes`]: #method.to_be_bytes
70     /// [`to_le_bytes`]: #method.to_le_bytes
71     ///
72     /// # Examples
73     ///
74     /// ```
75     /// use num_traits::ToBytes;
76     ///
77     /// #[cfg(target_endian = "big")]
78     /// let expected = [0x12, 0x34, 0x56, 0x78];
79     ///
80     /// #[cfg(target_endian = "little")]
81     /// let expected = [0x78, 0x56, 0x34, 0x12];
82     ///
83     /// let bytes = ToBytes::to_ne_bytes(&0x12345678u32);
84     /// assert_eq!(bytes, expected)
85     /// ```
to_ne_bytes(&self) -> Self::Bytes86     fn to_ne_bytes(&self) -> Self::Bytes {
87         #[cfg(target_endian = "big")]
88         let bytes = self.to_be_bytes();
89         #[cfg(target_endian = "little")]
90         let bytes = self.to_le_bytes();
91         bytes
92     }
93 }
94 
95 pub trait FromBytes: Sized {
96     type Bytes: NumBytes + ?Sized;
97 
98     /// Create a number from its representation as a byte array in big endian.
99     ///
100     /// # Examples
101     ///
102     /// ```
103     /// use num_traits::FromBytes;
104     ///
105     /// let value: u32 = FromBytes::from_be_bytes(&[0x12, 0x34, 0x56, 0x78]);
106     /// assert_eq!(value, 0x12345678);
107     /// ```
from_be_bytes(bytes: &Self::Bytes) -> Self108     fn from_be_bytes(bytes: &Self::Bytes) -> Self;
109 
110     /// Create a number from its representation as a byte array in little endian.
111     ///
112     /// # Examples
113     ///
114     /// ```
115     /// use num_traits::FromBytes;
116     ///
117     /// let value: u32 = FromBytes::from_le_bytes(&[0x78, 0x56, 0x34, 0x12]);
118     /// assert_eq!(value, 0x12345678);
119     /// ```
from_le_bytes(bytes: &Self::Bytes) -> Self120     fn from_le_bytes(bytes: &Self::Bytes) -> Self;
121 
122     /// Create a number from its memory representation as a byte array in native endianness.
123     ///
124     /// As the target platform's native endianness is used,
125     /// portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead.
126     ///
127     /// [`from_be_bytes`]: #method.from_be_bytes
128     /// [`from_le_bytes`]: #method.from_le_bytes
129     ///
130     /// # Examples
131     ///
132     /// ```
133     /// use num_traits::FromBytes;
134     ///
135     /// #[cfg(target_endian = "big")]
136     /// let bytes = [0x12, 0x34, 0x56, 0x78];
137     ///
138     /// #[cfg(target_endian = "little")]
139     /// let bytes = [0x78, 0x56, 0x34, 0x12];
140     ///
141     /// let value: u32 = FromBytes::from_ne_bytes(&bytes);
142     /// assert_eq!(value, 0x12345678)
143     /// ```
from_ne_bytes(bytes: &Self::Bytes) -> Self144     fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
145         #[cfg(target_endian = "big")]
146         let this = Self::from_be_bytes(bytes);
147         #[cfg(target_endian = "little")]
148         let this = Self::from_le_bytes(bytes);
149         this
150     }
151 }
152 
153 macro_rules! float_to_from_bytes_impl {
154     ($T:ty, $L:expr) => {
155         #[cfg(has_float_to_from_bytes)]
156         impl ToBytes for $T {
157             type Bytes = [u8; $L];
158 
159             #[inline]
160             fn to_be_bytes(&self) -> Self::Bytes {
161                 <$T>::to_be_bytes(*self)
162             }
163 
164             #[inline]
165             fn to_le_bytes(&self) -> Self::Bytes {
166                 <$T>::to_le_bytes(*self)
167             }
168 
169             #[inline]
170             fn to_ne_bytes(&self) -> Self::Bytes {
171                 <$T>::to_ne_bytes(*self)
172             }
173         }
174 
175         #[cfg(has_float_to_from_bytes)]
176         impl FromBytes for $T {
177             type Bytes = [u8; $L];
178 
179             #[inline]
180             fn from_be_bytes(bytes: &Self::Bytes) -> Self {
181                 <$T>::from_be_bytes(*bytes)
182             }
183 
184             #[inline]
185             fn from_le_bytes(bytes: &Self::Bytes) -> Self {
186                 <$T>::from_le_bytes(*bytes)
187             }
188 
189             #[inline]
190             fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
191                 <$T>::from_ne_bytes(*bytes)
192             }
193         }
194 
195         #[cfg(not(has_float_to_from_bytes))]
196         impl ToBytes for $T {
197             type Bytes = [u8; $L];
198 
199             #[inline]
200             fn to_be_bytes(&self) -> Self::Bytes {
201                 ToBytes::to_be_bytes(&self.to_bits())
202             }
203 
204             #[inline]
205             fn to_le_bytes(&self) -> Self::Bytes {
206                 ToBytes::to_le_bytes(&self.to_bits())
207             }
208 
209             #[inline]
210             fn to_ne_bytes(&self) -> Self::Bytes {
211                 ToBytes::to_ne_bytes(&self.to_bits())
212             }
213         }
214 
215         #[cfg(not(has_float_to_from_bytes))]
216         impl FromBytes for $T {
217             type Bytes = [u8; $L];
218 
219             #[inline]
220             fn from_be_bytes(bytes: &Self::Bytes) -> Self {
221                 Self::from_bits(FromBytes::from_be_bytes(bytes))
222             }
223 
224             #[inline]
225             fn from_le_bytes(bytes: &Self::Bytes) -> Self {
226                 Self::from_bits(FromBytes::from_le_bytes(bytes))
227             }
228 
229             #[inline]
230             fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
231                 Self::from_bits(FromBytes::from_ne_bytes(bytes))
232             }
233         }
234     };
235 }
236 
237 macro_rules! int_to_from_bytes_impl {
238     ($T:ty, $L:expr) => {
239         #[cfg(has_int_to_from_bytes)]
240         impl ToBytes for $T {
241             type Bytes = [u8; $L];
242 
243             #[inline]
244             fn to_be_bytes(&self) -> Self::Bytes {
245                 <$T>::to_be_bytes(*self)
246             }
247 
248             #[inline]
249             fn to_le_bytes(&self) -> Self::Bytes {
250                 <$T>::to_le_bytes(*self)
251             }
252 
253             #[inline]
254             fn to_ne_bytes(&self) -> Self::Bytes {
255                 <$T>::to_ne_bytes(*self)
256             }
257         }
258 
259         #[cfg(has_int_to_from_bytes)]
260         impl FromBytes for $T {
261             type Bytes = [u8; $L];
262 
263             #[inline]
264             fn from_be_bytes(bytes: &Self::Bytes) -> Self {
265                 <$T>::from_be_bytes(*bytes)
266             }
267 
268             #[inline]
269             fn from_le_bytes(bytes: &Self::Bytes) -> Self {
270                 <$T>::from_le_bytes(*bytes)
271             }
272 
273             #[inline]
274             fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
275                 <$T>::from_ne_bytes(*bytes)
276             }
277         }
278 
279         #[cfg(not(has_int_to_from_bytes))]
280         impl ToBytes for $T {
281             type Bytes = [u8; $L];
282 
283             #[inline]
284             fn to_be_bytes(&self) -> Self::Bytes {
285                 <$T as ToBytes>::to_ne_bytes(&<$T>::to_be(*self))
286             }
287 
288             #[inline]
289             fn to_le_bytes(&self) -> Self::Bytes {
290                 <$T as ToBytes>::to_ne_bytes(&<$T>::to_le(*self))
291             }
292 
293             #[inline]
294             fn to_ne_bytes(&self) -> Self::Bytes {
295                 unsafe { transmute(*self) }
296             }
297         }
298 
299         #[cfg(not(has_int_to_from_bytes))]
300         impl FromBytes for $T {
301             type Bytes = [u8; $L];
302 
303             #[inline]
304             fn from_be_bytes(bytes: &Self::Bytes) -> Self {
305                 Self::from_be(<Self as FromBytes>::from_ne_bytes(bytes))
306             }
307 
308             #[inline]
309             fn from_le_bytes(bytes: &Self::Bytes) -> Self {
310                 Self::from_le(<Self as FromBytes>::from_ne_bytes(bytes))
311             }
312 
313             #[inline]
314             fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
315                 unsafe { transmute(*bytes) }
316             }
317         }
318     };
319 }
320 
321 int_to_from_bytes_impl!(u8, 1);
322 int_to_from_bytes_impl!(u16, 2);
323 int_to_from_bytes_impl!(u32, 4);
324 int_to_from_bytes_impl!(u64, 8);
325 int_to_from_bytes_impl!(u128, 16);
326 #[cfg(target_pointer_width = "64")]
327 int_to_from_bytes_impl!(usize, 8);
328 #[cfg(target_pointer_width = "32")]
329 int_to_from_bytes_impl!(usize, 4);
330 
331 int_to_from_bytes_impl!(i8, 1);
332 int_to_from_bytes_impl!(i16, 2);
333 int_to_from_bytes_impl!(i32, 4);
334 int_to_from_bytes_impl!(i64, 8);
335 int_to_from_bytes_impl!(i128, 16);
336 #[cfg(target_pointer_width = "64")]
337 int_to_from_bytes_impl!(isize, 8);
338 #[cfg(target_pointer_width = "32")]
339 int_to_from_bytes_impl!(isize, 4);
340 
341 float_to_from_bytes_impl!(f32, 4);
342 float_to_from_bytes_impl!(f64, 8);
343 
344 #[cfg(test)]
345 mod tests {
346     use super::*;
347 
348     macro_rules! check_to_from_bytes {
349         ($( $ty:ty )+) => {$({
350             let n = 1;
351             let be = <$ty as ToBytes>::to_be_bytes(&n);
352             let le = <$ty as ToBytes>::to_le_bytes(&n);
353             let ne = <$ty as ToBytes>::to_ne_bytes(&n);
354 
355             assert_eq!(*be.last().unwrap(), 1);
356             assert_eq!(*le.first().unwrap(), 1);
357             if cfg!(target_endian = "big") {
358                 assert_eq!(*ne.last().unwrap(), 1);
359             } else {
360                 assert_eq!(*ne.first().unwrap(), 1);
361             }
362 
363             assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n);
364             assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n);
365             if cfg!(target_endian = "big") {
366                 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n);
367             } else {
368                 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n);
369             }
370         })+}
371     }
372 
373     #[test]
convert_between_int_and_bytes()374     fn convert_between_int_and_bytes() {
375         check_to_from_bytes!(u8 u16 u32 u64 u128 usize);
376         check_to_from_bytes!(i8 i16 i32 i64 i128 isize);
377     }
378 
379     #[test]
convert_between_float_and_bytes()380     fn convert_between_float_and_bytes() {
381         macro_rules! check_to_from_bytes {
382             ($( $ty:ty )+) => {$(
383                 let n: $ty = 3.14;
384 
385                 let be = <$ty as ToBytes>::to_be_bytes(&n);
386                 let le = <$ty as ToBytes>::to_le_bytes(&n);
387                 let ne = <$ty as ToBytes>::to_ne_bytes(&n);
388 
389                 assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n);
390                 assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n);
391                 if cfg!(target_endian = "big") {
392                     assert_eq!(ne, be);
393                     assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n);
394                 } else {
395                     assert_eq!(ne, le);
396                     assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n);
397                 }
398             )+}
399         }
400 
401         check_to_from_bytes!(f32 f64);
402     }
403 }
404