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