1use core::borrow::{Borrow, BorrowMut};
2use core::cmp::{Eq, Ord, PartialEq, PartialOrd};
3use core::fmt::Debug;
4use core::hash::Hash;
5
6pub 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
20impl<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
35pub 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 /// ```
48 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 /// ```
60 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 /// ```
84 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
93pub 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 /// ```
106 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 /// ```
118 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 /// ```
142 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
151macro_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
193macro_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
235int_to_from_bytes_impl!(u8, 1);
236int_to_from_bytes_impl!(u16, 2);
237int_to_from_bytes_impl!(u32, 4);
238int_to_from_bytes_impl!(u64, 8);
239int_to_from_bytes_impl!(u128, 16);
240#[cfg(target_pointer_width = "64")]
241int_to_from_bytes_impl!(usize, 8);
242#[cfg(target_pointer_width = "32")]
243int_to_from_bytes_impl!(usize, 4);
244
245int_to_from_bytes_impl!(i8, 1);
246int_to_from_bytes_impl!(i16, 2);
247int_to_from_bytes_impl!(i32, 4);
248int_to_from_bytes_impl!(i64, 8);
249int_to_from_bytes_impl!(i128, 16);
250#[cfg(target_pointer_width = "64")]
251int_to_from_bytes_impl!(isize, 8);
252#[cfg(target_pointer_width = "32")]
253int_to_from_bytes_impl!(isize, 4);
254
255float_to_from_bytes_impl!(f32, 4);
256float_to_from_bytes_impl!(f64, 8);
257
258#[cfg(test)]
259mod 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]
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]
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