num_traits/ops/
bytes.rs
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 fn to_be_bytes(&self) -> Self::Bytes;
51
52 fn to_le_bytes(&self) -> Self::Bytes;
63
64 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 fn from_be_bytes(bytes: &Self::Bytes) -> Self;
109
110 fn from_le_bytes(bytes: &Self::Bytes) -> Self;
121
122 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}