1use core::borrow::{Borrow, BorrowMut};
2use core::cmp::{Eq, Ord, PartialEq, PartialOrd};
3use core::fmt::Debug;
4use core::hash::Hash;
5#[cfg(not(has_int_to_from_bytes))]
6use core::mem::transmute;
7
8pub 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
22impl<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
37pub 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 /// ```
50 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 /// ```
62 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 /// ```
86 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
95pub 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 /// ```
108 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 /// ```
120 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 /// ```
144 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
153macro_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
237macro_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
321int_to_from_bytes_impl!(u8, 1);
322int_to_from_bytes_impl!(u16, 2);
323int_to_from_bytes_impl!(u32, 4);
324int_to_from_bytes_impl!(u64, 8);
325int_to_from_bytes_impl!(u128, 16);
326#[cfg(target_pointer_width = "64")]
327int_to_from_bytes_impl!(usize, 8);
328#[cfg(target_pointer_width = "32")]
329int_to_from_bytes_impl!(usize, 4);
330
331int_to_from_bytes_impl!(i8, 1);
332int_to_from_bytes_impl!(i16, 2);
333int_to_from_bytes_impl!(i32, 4);
334int_to_from_bytes_impl!(i64, 8);
335int_to_from_bytes_impl!(i128, 16);
336#[cfg(target_pointer_width = "64")]
337int_to_from_bytes_impl!(isize, 8);
338#[cfg(target_pointer_width = "32")]
339int_to_from_bytes_impl!(isize, 4);
340
341float_to_from_bytes_impl!(f32, 4);
342float_to_from_bytes_impl!(f64, 8);
343
344#[cfg(test)]
345mod 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]
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]
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