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 | /// ``` |
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 | |
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 | /// ``` |
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 | |
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] |
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 | |