xref: /linux/rust/zerocopy/src/byteorder.rs (revision 499dc02cd545258b8ebd6f52fac226c6263768e9)
1 // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
2 
3 // Copyright 2019 The Fuchsia Authors
4 //
5 // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
6 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
7 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
8 // This file may not be copied, modified, or distributed except according to
9 // those terms.
10 
11 //! Byte order-aware numeric primitives.
12 //!
13 //! This module contains equivalents of the native multi-byte integer types with
14 //! no alignment requirement and supporting byte order conversions.
15 //!
16 //! For each native multi-byte integer type - `u16`, `i16`, `u32`, etc - and
17 //! floating point type - `f32` and `f64` - an equivalent type is defined by
18 //! this module - [`U16`], [`I16`], [`U32`], [`F32`], [`F64`], etc. Unlike their
19 //! native counterparts, these types have alignment 1, and take a type parameter
20 //! specifying the byte order in which the bytes are stored in memory. Each type
21 //! implements this crate's relevant conversion and marker traits.
22 //!
23 //! These two properties, taken together, make these types useful for defining
24 //! data structures whose memory layout matches a wire format such as that of a
25 //! network protocol or a file format. Such formats often have multi-byte values
26 //! at offsets that do not respect the alignment requirements of the equivalent
27 //! native types, and stored in a byte order not necessarily the same as that of
28 //! the target platform.
29 //!
30 //! Type aliases are provided for common byte orders in the [`big_endian`],
31 //! [`little_endian`], [`network_endian`], and [`native_endian`] submodules.
32 //! Note that network-endian is a synonym for big-endian.
33 //!
34 //! # Example
35 //!
36 //! One use of these types is for representing network packet formats, such as
37 //! UDP:
38 //!
39 //! ```rust
40 //! use zerocopy::{*, byteorder::network_endian::U16};
41 //! # use zerocopy_derive::*;
42 //!
43 //! #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
44 //! #[repr(C)]
45 //! struct UdpHeader {
46 //!     src_port: U16,
47 //!     dst_port: U16,
48 //!     length: U16,
49 //!     checksum: U16,
50 //! }
51 //!
52 //! #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
53 //! #[repr(C, packed)]
54 //! struct UdpPacket {
55 //!     header: UdpHeader,
56 //!     body: [u8],
57 //! }
58 //!
59 //! impl UdpPacket {
60 //!     fn parse(bytes: &[u8]) -> Option<&UdpPacket> {
61 //!         UdpPacket::ref_from_bytes(bytes).ok()
62 //!     }
63 //! }
64 //! ```
65 
66 use core::{
67     convert::{TryFrom, TryInto},
68     fmt::{Binary, Debug, LowerHex, Octal, UpperHex},
69     hash::Hash,
70     num::TryFromIntError,
71 };
72 
73 use super::*;
74 
75 /// A type-level representation of byte order.
76 ///
77 /// This type is implemented by [`BigEndian`] and [`LittleEndian`], which
78 /// represent big-endian and little-endian byte order respectively. This module
79 /// also provides a number of useful aliases for those types: [`NativeEndian`],
80 /// [`NetworkEndian`], [`BE`], and [`LE`].
81 ///
82 /// `ByteOrder` types can be used to specify the byte order of the types in this
83 /// module - for example, [`U32<BigEndian>`] is a 32-bit integer stored in
84 /// big-endian byte order.
85 ///
86 /// [`U32<BigEndian>`]: U32
87 pub trait ByteOrder:
88     Copy + Clone + Debug + Display + Eq + PartialEq + Ord + PartialOrd + Hash + private::Sealed
89 {
90     #[doc(hidden)]
91     const ORDER: Order;
92 }
93 
94 mod private {
95     pub trait Sealed {}
96 
97     impl Sealed for super::BigEndian {}
98     impl Sealed for super::LittleEndian {}
99 }
100 
101 #[allow(missing_copy_implementations, missing_debug_implementations)]
102 #[doc(hidden)]
103 pub enum Order {
104     BigEndian,
105     LittleEndian,
106 }
107 
108 /// Big-endian byte order.
109 ///
110 /// See [`ByteOrder`] for more details.
111 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
112 pub enum BigEndian {}
113 
114 impl ByteOrder for BigEndian {
115     const ORDER: Order = Order::BigEndian;
116 }
117 
118 impl Display for BigEndian {
119     #[inline]
120     fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
121         match *self {}
122     }
123 }
124 
125 /// Little-endian byte order.
126 ///
127 /// See [`ByteOrder`] for more details.
128 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
129 pub enum LittleEndian {}
130 
131 impl ByteOrder for LittleEndian {
132     const ORDER: Order = Order::LittleEndian;
133 }
134 
135 impl Display for LittleEndian {
136     #[inline]
137     fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
138         match *self {}
139     }
140 }
141 
142 /// The endianness used by this platform.
143 ///
144 /// This is a type alias for [`BigEndian`] or [`LittleEndian`] depending on the
145 /// endianness of the target platform.
146 #[cfg(target_endian = "big")]
147 pub type NativeEndian = BigEndian;
148 
149 /// The endianness used by this platform.
150 ///
151 /// This is a type alias for [`BigEndian`] or [`LittleEndian`] depending on the
152 /// endianness of the target platform.
153 #[cfg(target_endian = "little")]
154 pub type NativeEndian = LittleEndian;
155 
156 /// The endianness used in many network protocols.
157 ///
158 /// This is a type alias for [`BigEndian`].
159 pub type NetworkEndian = BigEndian;
160 
161 /// A type alias for [`BigEndian`].
162 pub type BE = BigEndian;
163 
164 /// A type alias for [`LittleEndian`].
165 pub type LE = LittleEndian;
166 
167 macro_rules! impl_fmt_trait {
168     ($name:ident, $native:ident, $trait:ident) => {
169         impl<O: ByteOrder> $trait for $name<O> {
170             #[inline(always)]
171             fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
172                 $trait::fmt(&self.get(), f)
173             }
174         }
175     };
176 }
177 
178 macro_rules! impl_fmt_traits {
179     ($name:ident, $native:ident, "floating point number") => {
180         impl_fmt_trait!($name, $native, Display);
181     };
182     ($name:ident, $native:ident, "unsigned integer") => {
183         impl_fmt_traits!($name, $native, @all_types);
184     };
185     ($name:ident, $native:ident, "signed integer") => {
186         impl_fmt_traits!($name, $native, @all_types);
187     };
188     ($name:ident, $native:ident, @all_types) => {
189         impl_fmt_trait!($name, $native, Display);
190         impl_fmt_trait!($name, $native, Octal);
191         impl_fmt_trait!($name, $native, LowerHex);
192         impl_fmt_trait!($name, $native, UpperHex);
193         impl_fmt_trait!($name, $native, Binary);
194     };
195 }
196 
197 macro_rules! impl_ops_traits {
198     ($name:ident, $native:ident, "floating point number") => {
199         impl_ops_traits!($name, $native, @all_types);
200         impl_ops_traits!($name, $native, @signed_integer_floating_point);
201 
202         impl<O: ByteOrder> PartialOrd for $name<O> {
203             #[inline(always)]
204             fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
205                 self.get().partial_cmp(&other.get())
206             }
207         }
208     };
209     ($name:ident, $native:ident, "unsigned integer") => {
210         impl_ops_traits!($name, $native, @signed_unsigned_integer);
211         impl_ops_traits!($name, $native, @all_types);
212     };
213     ($name:ident, $native:ident, "signed integer") => {
214         impl_ops_traits!($name, $native, @signed_unsigned_integer);
215         impl_ops_traits!($name, $native, @signed_integer_floating_point);
216         impl_ops_traits!($name, $native, @all_types);
217     };
218     ($name:ident, $native:ident, @signed_unsigned_integer) => {
219         impl_ops_traits!(@without_byteorder_swap $name, $native, BitAnd, bitand, BitAndAssign, bitand_assign);
220         impl_ops_traits!(@without_byteorder_swap $name, $native, BitOr, bitor, BitOrAssign, bitor_assign);
221         impl_ops_traits!(@without_byteorder_swap $name, $native, BitXor, bitxor, BitXorAssign, bitxor_assign);
222         impl_ops_traits!(@with_byteorder_swap $name, $native, Shl, shl, ShlAssign, shl_assign);
223         impl_ops_traits!(@with_byteorder_swap $name, $native, Shr, shr, ShrAssign, shr_assign);
224 
225         impl<O> core::ops::Not for $name<O> {
226             type Output = $name<O>;
227 
228             #[inline(always)]
229             fn not(self) -> $name<O> {
230                  let self_native = $native::from_ne_bytes(self.0);
231                  $name((!self_native).to_ne_bytes(), PhantomData)
232             }
233         }
234 
235         impl<O: ByteOrder> PartialOrd for $name<O> {
236             #[inline(always)]
237             fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
238                 Some(self.cmp(other))
239             }
240         }
241 
242         impl<O: ByteOrder> Ord for $name<O> {
243             #[inline(always)]
244             fn cmp(&self, other: &Self) -> Ordering {
245                 self.get().cmp(&other.get())
246             }
247         }
248 
249         impl<O: ByteOrder> PartialOrd<$native> for $name<O> {
250             #[inline(always)]
251             fn partial_cmp(&self, other: &$native) -> Option<Ordering> {
252                 self.get().partial_cmp(other)
253             }
254         }
255     };
256     ($name:ident, $native:ident, @signed_integer_floating_point) => {
257         impl<O: ByteOrder> core::ops::Neg for $name<O> {
258             type Output = $name<O>;
259 
260             #[inline(always)]
261             fn neg(self) -> $name<O> {
262                 let self_native: $native = self.get();
263                 #[allow(clippy::arithmetic_side_effects)]
264                 $name::<O>::new(-self_native)
265             }
266         }
267     };
268     ($name:ident, $native:ident, @all_types) => {
269         impl_ops_traits!(@with_byteorder_swap $name, $native, Add, add, AddAssign, add_assign);
270         impl_ops_traits!(@with_byteorder_swap $name, $native, Div, div, DivAssign, div_assign);
271         impl_ops_traits!(@with_byteorder_swap $name, $native, Mul, mul, MulAssign, mul_assign);
272         impl_ops_traits!(@with_byteorder_swap $name, $native, Rem, rem, RemAssign, rem_assign);
273         impl_ops_traits!(@with_byteorder_swap $name, $native, Sub, sub, SubAssign, sub_assign);
274     };
275     (@with_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => {
276         impl<O: ByteOrder> core::ops::$trait<$name<O>> for $name<O> {
277             type Output = $name<O>;
278 
279             #[inline(always)]
280             fn $method(self, rhs: $name<O>) -> $name<O> {
281                 let self_native: $native = self.get();
282                 let rhs_native: $native = rhs.get();
283                 let result_native = core::ops::$trait::$method(self_native, rhs_native);
284                 $name::<O>::new(result_native)
285             }
286         }
287 
288         impl<O: ByteOrder> core::ops::$trait<$name<O>> for $native {
289             type Output = $name<O>;
290 
291             #[inline(always)]
292             fn $method(self, rhs: $name<O>) -> $name<O> {
293                 let rhs_native: $native = rhs.get();
294                 let result_native = core::ops::$trait::$method(self, rhs_native);
295                 $name::<O>::new(result_native)
296             }
297         }
298 
299         impl<O: ByteOrder> core::ops::$trait<$native> for $name<O> {
300             type Output = $name<O>;
301 
302             #[inline(always)]
303             fn $method(self, rhs: $native) -> $name<O> {
304                 let self_native: $native = self.get();
305                 let result_native = core::ops::$trait::$method(self_native, rhs);
306                 $name::<O>::new(result_native)
307             }
308         }
309 
310         impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $name<O> {
311             #[inline(always)]
312             fn $method_assign(&mut self, rhs: $name<O>) {
313                 *self = core::ops::$trait::$method(*self, rhs);
314             }
315         }
316 
317         impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $native {
318             #[inline(always)]
319             fn $method_assign(&mut self, rhs: $name<O>) {
320                 let rhs_native: $native = rhs.get();
321                 *self = core::ops::$trait::$method(*self, rhs_native);
322             }
323         }
324 
325         impl<O: ByteOrder> core::ops::$trait_assign<$native> for $name<O> {
326             #[inline(always)]
327             fn $method_assign(&mut self, rhs: $native) {
328                 *self = core::ops::$trait::$method(*self, rhs);
329             }
330         }
331     };
332     // Implement traits in terms of the same trait on the native type, but
333     // without performing a byte order swap when both operands are byteorder
334     // types. This only works for bitwise operations like `&`, `|`, etc.
335     //
336     // When only one operand is a byteorder type, we still need to perform a
337     // byteorder swap.
338     (@without_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => {
339         impl<O: ByteOrder> core::ops::$trait<$name<O>> for $name<O> {
340             type Output = $name<O>;
341 
342             #[inline(always)]
343             fn $method(self, rhs: $name<O>) -> $name<O> {
344                 let self_native = $native::from_ne_bytes(self.0);
345                 let rhs_native = $native::from_ne_bytes(rhs.0);
346                 let result_native = core::ops::$trait::$method(self_native, rhs_native);
347                 $name(result_native.to_ne_bytes(), PhantomData)
348             }
349         }
350 
351         impl<O: ByteOrder> core::ops::$trait<$name<O>> for $native {
352             type Output = $name<O>;
353 
354             #[inline(always)]
355             fn $method(self, rhs: $name<O>) -> $name<O> {
356                 // No runtime cost - just byte packing
357                 let rhs_native = $native::from_ne_bytes(rhs.0);
358                 // (Maybe) runtime cost - byte order swap
359                 let slf_byteorder = $name::<O>::new(self);
360                 // No runtime cost - just byte packing
361                 let slf_native = $native::from_ne_bytes(slf_byteorder.0);
362                 // Runtime cost - perform the operation
363                 let result_native = core::ops::$trait::$method(slf_native, rhs_native);
364                 // No runtime cost - just byte unpacking
365                 $name(result_native.to_ne_bytes(), PhantomData)
366             }
367         }
368 
369         impl<O: ByteOrder> core::ops::$trait<$native> for $name<O> {
370             type Output = $name<O>;
371 
372             #[inline(always)]
373             fn $method(self, rhs: $native) -> $name<O> {
374                 // (Maybe) runtime cost - byte order swap
375                 let rhs_byteorder = $name::<O>::new(rhs);
376                 // No runtime cost - just byte packing
377                 let rhs_native = $native::from_ne_bytes(rhs_byteorder.0);
378                 // No runtime cost - just byte packing
379                 let slf_native = $native::from_ne_bytes(self.0);
380                 // Runtime cost - perform the operation
381                 let result_native = core::ops::$trait::$method(slf_native, rhs_native);
382                 // No runtime cost - just byte unpacking
383                 $name(result_native.to_ne_bytes(), PhantomData)
384             }
385         }
386 
387         impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $name<O> {
388             #[inline(always)]
389             fn $method_assign(&mut self, rhs: $name<O>) {
390                 *self = core::ops::$trait::$method(*self, rhs);
391             }
392         }
393 
394         impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $native {
395             #[inline(always)]
396             fn $method_assign(&mut self, rhs: $name<O>) {
397                 // (Maybe) runtime cost - byte order swap
398                 let rhs_native = rhs.get();
399                 // Runtime cost - perform the operation
400                 *self = core::ops::$trait::$method(*self, rhs_native);
401             }
402         }
403 
404         impl<O: ByteOrder> core::ops::$trait_assign<$native> for $name<O> {
405             #[inline(always)]
406             fn $method_assign(&mut self, rhs: $native) {
407                 *self = core::ops::$trait::$method(*self, rhs);
408             }
409         }
410     };
411 }
412 
413 macro_rules! doc_comment {
414     ($x:expr, $($tt:tt)*) => {
415         #[doc = $x]
416         $($tt)*
417     };
418 }
419 
420 macro_rules! define_max_value_constant {
421     ($name:ident, $bytes:expr, "unsigned integer") => {
422         /// The maximum value.
423         ///
424         /// This constant should be preferred to constructing a new value using
425         /// `new`, as `new` may perform an endianness swap depending on the
426         /// endianness `O` and the endianness of the platform.
427         pub const MAX_VALUE: $name<O> = $name([0xFFu8; $bytes], PhantomData);
428     };
429     // We don't provide maximum and minimum value constants for signed values
430     // and floats because there's no way to do it generically - it would require
431     // a different value depending on the value of the `ByteOrder` type
432     // parameter. Currently, one workaround would be to provide implementations
433     // for concrete implementations of that trait. In the long term, if we are
434     // ever able to make the `new` constructor a const fn, we could use that
435     // instead.
436     ($name:ident, $bytes:expr, "signed integer") => {};
437     ($name:ident, $bytes:expr, "floating point number") => {};
438 }
439 
440 macro_rules! define_type {
441     (
442         $article:ident,
443         $description:expr,
444         $name:ident,
445         $native:ident,
446         $bits:expr,
447         $bytes:expr,
448         $from_be_fn:path,
449         $to_be_fn:path,
450         $from_le_fn:path,
451         $to_le_fn:path,
452         $number_kind:tt,
453         [$($larger_native:ty),*],
454         [$($larger_native_try:ty),*],
455         [$($larger_byteorder:ident),*],
456         [$($larger_byteorder_try:ident),*]
457     ) => {
458         doc_comment! {
459             concat!($description, " stored in a given byte order.
460 
461 `", stringify!($name), "` is like the native `", stringify!($native), "` type with
462 two major differences: First, it has no alignment requirement (its alignment is 1).
463 Second, the endianness of its memory layout is given by the type parameter `O`,
464 which can be any type which implements [`ByteOrder`]. In particular, this refers
465 to [`BigEndian`], [`LittleEndian`], [`NativeEndian`], and [`NetworkEndian`].
466 
467 ", stringify!($article), " `", stringify!($name), "` can be constructed using
468 the [`new`] method, and its contained value can be obtained as a native
469 `",stringify!($native), "` using the [`get`] method, or updated in place with
470 the [`set`] method. In all cases, if the endianness `O` is not the same as the
471 endianness of the current platform, an endianness swap will be performed in
472 order to uphold the invariants that a) the layout of `", stringify!($name), "`
473 has endianness `O` and that, b) the layout of `", stringify!($native), "` has
474 the platform's native endianness.
475 
476 `", stringify!($name), "` implements [`FromBytes`], [`IntoBytes`], and [`Unaligned`],
477 making it useful for parsing and serialization. See the module documentation for an
478 example of how it can be used for parsing UDP packets.
479 
480 [`new`]: crate::byteorder::", stringify!($name), "::new
481 [`get`]: crate::byteorder::", stringify!($name), "::get
482 [`set`]: crate::byteorder::", stringify!($name), "::set
483 [`FromBytes`]: crate::FromBytes
484 [`IntoBytes`]: crate::IntoBytes
485 [`Unaligned`]: crate::Unaligned"),
486             #[derive(Copy, Clone, Eq, PartialEq, Hash)]
487             #[cfg_attr(any(feature = "derive", test), derive(KnownLayout, Immutable, FromBytes, IntoBytes, Unaligned))]
488             #[repr(transparent)]
489             pub struct $name<O>([u8; $bytes], PhantomData<O>);
490         }
491 
492         #[cfg(not(any(feature = "derive", test)))]
493         impl_known_layout!(O => $name<O>);
494 
495         #[allow(unused_unsafe)] // Unused when `feature = "derive"`.
496         // SAFETY: `$name<O>` is `repr(transparent)`, and so it has the same
497         // layout as its only non-zero field, which is a `u8` array. `u8` arrays
498         // are `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`,
499         // `IntoBytes`, and `Unaligned`.
500         #[allow(clippy::multiple_unsafe_ops_per_block)]
501         const _: () = unsafe {
502             impl_or_verify!(O => Immutable for $name<O>);
503             impl_or_verify!(O => TryFromBytes for $name<O>);
504             impl_or_verify!(O => FromZeros for $name<O>);
505             impl_or_verify!(O => FromBytes for $name<O>);
506             impl_or_verify!(O => IntoBytes for $name<O>);
507             impl_or_verify!(O => Unaligned for $name<O>);
508         };
509 
510         impl<O> Default for $name<O> {
511             #[inline(always)]
512             fn default() -> $name<O> {
513                 $name::ZERO
514             }
515         }
516 
517         impl<O> $name<O> {
518             /// The value zero.
519             ///
520             /// This constant should be preferred to constructing a new value
521             /// using `new`, as `new` may perform an endianness swap depending
522             /// on the endianness and platform.
523             pub const ZERO: $name<O> = $name([0u8; $bytes], PhantomData);
524 
525             define_max_value_constant!($name, $bytes, $number_kind);
526 
527             /// Constructs a new value from bytes which are already in `O` byte
528             /// order.
529             #[must_use = "has no side effects"]
530             #[inline(always)]
531             pub const fn from_bytes(bytes: [u8; $bytes]) -> $name<O> {
532                 $name(bytes, PhantomData)
533             }
534 
535             /// Extracts the bytes of `self` without swapping the byte order.
536             ///
537             /// The returned bytes will be in `O` byte order.
538             #[must_use = "has no side effects"]
539             #[inline(always)]
540             pub const fn to_bytes(self) -> [u8; $bytes] {
541                 self.0
542             }
543         }
544 
545         impl<O: ByteOrder> $name<O> {
546             maybe_const_trait_bounded_fn! {
547                 /// Constructs a new value, possibly performing an endianness
548                 /// swap to guarantee that the returned value has endianness
549                 /// `O`.
550                 #[must_use = "has no side effects"]
551                 #[inline(always)]
552                 pub const fn new(n: $native) -> $name<O> {
553                     let bytes = match O::ORDER {
554                         Order::BigEndian => $to_be_fn(n),
555                         Order::LittleEndian => $to_le_fn(n),
556                     };
557 
558                     $name(bytes, PhantomData)
559                 }
560             }
561 
562             maybe_const_trait_bounded_fn! {
563                 /// Returns the value as a primitive type, possibly performing
564                 /// an endianness swap to guarantee that the return value has
565                 /// the endianness of the native platform.
566                 #[must_use = "has no side effects"]
567                 #[inline(always)]
568                 pub const fn get(self) -> $native {
569                     match O::ORDER {
570                         Order::BigEndian => $from_be_fn(self.0),
571                         Order::LittleEndian => $from_le_fn(self.0),
572                     }
573                 }
574             }
575 
576             /// Updates the value in place as a primitive type, possibly
577             /// performing an endianness swap to guarantee that the stored value
578             /// has the endianness `O`.
579             #[inline(always)]
580             pub fn set(&mut self, n: $native) {
581                 *self = Self::new(n);
582             }
583         }
584 
585         // The reasoning behind which traits to implement here is to only
586         // implement traits which won't cause inference issues. Notably,
587         // comparison traits like PartialEq and PartialOrd tend to cause
588         // inference issues.
589 
590         impl<O: ByteOrder> From<$name<O>> for [u8; $bytes] {
591             #[inline(always)]
592             fn from(x: $name<O>) -> [u8; $bytes] {
593                 x.0
594             }
595         }
596 
597         impl<O: ByteOrder> From<[u8; $bytes]> for $name<O> {
598             #[inline(always)]
599             fn from(bytes: [u8; $bytes]) -> $name<O> {
600                 $name(bytes, PhantomData)
601             }
602         }
603 
604         impl<O: ByteOrder> From<$name<O>> for $native {
605             #[inline(always)]
606             fn from(x: $name<O>) -> $native {
607                 x.get()
608             }
609         }
610 
611         impl<O: ByteOrder> From<$native> for $name<O> {
612             #[inline(always)]
613             fn from(x: $native) -> $name<O> {
614                 $name::new(x)
615             }
616         }
617 
618         $(
619             impl<O: ByteOrder> From<$name<O>> for $larger_native {
620                 #[inline(always)]
621                 fn from(x: $name<O>) -> $larger_native {
622                     x.get().into()
623                 }
624             }
625         )*
626 
627         $(
628             impl<O: ByteOrder> TryFrom<$larger_native_try> for $name<O> {
629                 type Error = TryFromIntError;
630                 #[inline(always)]
631                 fn try_from(x: $larger_native_try) -> Result<$name<O>, TryFromIntError> {
632                     $native::try_from(x).map($name::new)
633                 }
634             }
635         )*
636 
637         $(
638             impl<O: ByteOrder, P: ByteOrder> From<$name<O>> for $larger_byteorder<P> {
639                 #[inline(always)]
640                 fn from(x: $name<O>) -> $larger_byteorder<P> {
641                     $larger_byteorder::new(x.get().into())
642                 }
643             }
644         )*
645 
646         $(
647             impl<O: ByteOrder, P: ByteOrder> TryFrom<$larger_byteorder_try<P>> for $name<O> {
648                 type Error = TryFromIntError;
649                 #[inline(always)]
650                 fn try_from(x: $larger_byteorder_try<P>) -> Result<$name<O>, TryFromIntError> {
651                     x.get().try_into().map($name::new)
652                 }
653             }
654         )*
655 
656         impl<O> AsRef<[u8; $bytes]> for $name<O> {
657             #[inline(always)]
658             fn as_ref(&self) -> &[u8; $bytes] {
659                 &self.0
660             }
661         }
662 
663         impl<O> AsMut<[u8; $bytes]> for $name<O> {
664             #[inline(always)]
665             fn as_mut(&mut self) -> &mut [u8; $bytes] {
666                 &mut self.0
667             }
668         }
669 
670         impl<O> PartialEq<$name<O>> for [u8; $bytes] {
671             #[inline(always)]
672             fn eq(&self, other: &$name<O>) -> bool {
673                 self.eq(&other.0)
674             }
675         }
676 
677         impl<O> PartialEq<[u8; $bytes]> for $name<O> {
678             #[inline(always)]
679             fn eq(&self, other: &[u8; $bytes]) -> bool {
680                 self.0.eq(other)
681             }
682         }
683 
684         impl<O: ByteOrder> PartialEq<$native> for $name<O> {
685             #[inline(always)]
686             fn eq(&self, other: &$native) -> bool {
687                 self.get().eq(other)
688             }
689         }
690 
691         impl_fmt_traits!($name, $native, $number_kind);
692         impl_ops_traits!($name, $native, $number_kind);
693 
694         impl<O: ByteOrder> Debug for $name<O> {
695             #[inline]
696             fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
697                 // This results in a format like "U16(42)".
698                 f.debug_tuple(stringify!($name)).field(&self.get()).finish()
699             }
700         }
701     };
702 }
703 
704 define_type!(
705     A,
706     "A 16-bit unsigned integer",
707     U16,
708     u16,
709     16,
710     2,
711     u16::from_be_bytes,
712     u16::to_be_bytes,
713     u16::from_le_bytes,
714     u16::to_le_bytes,
715     "unsigned integer",
716     [u32, u64, u128, usize],
717     [u32, u64, u128, usize],
718     [U32, U64, U128, Usize],
719     [U32, U64, U128, Usize]
720 );
721 define_type!(
722     A,
723     "A 32-bit unsigned integer",
724     U32,
725     u32,
726     32,
727     4,
728     u32::from_be_bytes,
729     u32::to_be_bytes,
730     u32::from_le_bytes,
731     u32::to_le_bytes,
732     "unsigned integer",
733     [u64, u128],
734     [u64, u128],
735     [U64, U128],
736     [U64, U128]
737 );
738 define_type!(
739     A,
740     "A 64-bit unsigned integer",
741     U64,
742     u64,
743     64,
744     8,
745     u64::from_be_bytes,
746     u64::to_be_bytes,
747     u64::from_le_bytes,
748     u64::to_le_bytes,
749     "unsigned integer",
750     [u128],
751     [u128],
752     [U128],
753     [U128]
754 );
755 define_type!(
756     A,
757     "A 128-bit unsigned integer",
758     U128,
759     u128,
760     128,
761     16,
762     u128::from_be_bytes,
763     u128::to_be_bytes,
764     u128::from_le_bytes,
765     u128::to_le_bytes,
766     "unsigned integer",
767     [],
768     [],
769     [],
770     []
771 );
772 define_type!(
773     A,
774     "A word-sized unsigned integer",
775     Usize,
776     usize,
777     mem::size_of::<usize>() * 8,
778     mem::size_of::<usize>(),
779     usize::from_be_bytes,
780     usize::to_be_bytes,
781     usize::from_le_bytes,
782     usize::to_le_bytes,
783     "unsigned integer",
784     [],
785     [],
786     [],
787     []
788 );
789 define_type!(
790     An,
791     "A 16-bit signed integer",
792     I16,
793     i16,
794     16,
795     2,
796     i16::from_be_bytes,
797     i16::to_be_bytes,
798     i16::from_le_bytes,
799     i16::to_le_bytes,
800     "signed integer",
801     [i32, i64, i128, isize],
802     [i32, i64, i128, isize],
803     [I32, I64, I128, Isize],
804     [I32, I64, I128, Isize]
805 );
806 define_type!(
807     An,
808     "A 32-bit signed integer",
809     I32,
810     i32,
811     32,
812     4,
813     i32::from_be_bytes,
814     i32::to_be_bytes,
815     i32::from_le_bytes,
816     i32::to_le_bytes,
817     "signed integer",
818     [i64, i128],
819     [i64, i128],
820     [I64, I128],
821     [I64, I128]
822 );
823 define_type!(
824     An,
825     "A 64-bit signed integer",
826     I64,
827     i64,
828     64,
829     8,
830     i64::from_be_bytes,
831     i64::to_be_bytes,
832     i64::from_le_bytes,
833     i64::to_le_bytes,
834     "signed integer",
835     [i128],
836     [i128],
837     [I128],
838     [I128]
839 );
840 define_type!(
841     An,
842     "A 128-bit signed integer",
843     I128,
844     i128,
845     128,
846     16,
847     i128::from_be_bytes,
848     i128::to_be_bytes,
849     i128::from_le_bytes,
850     i128::to_le_bytes,
851     "signed integer",
852     [],
853     [],
854     [],
855     []
856 );
857 define_type!(
858     An,
859     "A word-sized signed integer",
860     Isize,
861     isize,
862     mem::size_of::<isize>() * 8,
863     mem::size_of::<isize>(),
864     isize::from_be_bytes,
865     isize::to_be_bytes,
866     isize::from_le_bytes,
867     isize::to_le_bytes,
868     "signed integer",
869     [],
870     [],
871     [],
872     []
873 );
874 
875 // FIXME(https://github.com/rust-lang/rust/issues/72447): Use the endianness
876 // conversion methods directly once those are const-stable.
877 macro_rules! define_float_conversion {
878     ($ty:ty, $bits:ident, $bytes:expr, $mod:ident) => {
879         mod $mod {
880             use super::*;
881 
882             define_float_conversion!($ty, $bits, $bytes, from_be_bytes, to_be_bytes);
883             define_float_conversion!($ty, $bits, $bytes, from_le_bytes, to_le_bytes);
884         }
885     };
886     ($ty:ty, $bits:ident, $bytes:expr, $from:ident, $to:ident) => {
887         // Clippy: The suggestion of using `from_bits()` instead doesn't work
888         // because `from_bits` is not const-stable on our MSRV.
889         #[allow(clippy::unnecessary_transmutes)]
890         pub(crate) const fn $from(bytes: [u8; $bytes]) -> $ty {
891             transmute!($bits::$from(bytes))
892         }
893 
894         pub(crate) const fn $to(f: $ty) -> [u8; $bytes] {
895             // Clippy: The suggestion of using `f.to_bits()` instead doesn't
896             // work because `to_bits` is not const-stable on our MSRV.
897             #[allow(clippy::unnecessary_transmutes)]
898             let bits: $bits = transmute!(f);
899             bits.$to()
900         }
901     };
902 }
903 
904 define_float_conversion!(f32, u32, 4, f32_ext);
905 define_float_conversion!(f64, u64, 8, f64_ext);
906 
907 define_type!(
908     An,
909     "A 32-bit floating point number",
910     F32,
911     f32,
912     32,
913     4,
914     f32_ext::from_be_bytes,
915     f32_ext::to_be_bytes,
916     f32_ext::from_le_bytes,
917     f32_ext::to_le_bytes,
918     "floating point number",
919     [f64],
920     [],
921     [F64],
922     []
923 );
924 define_type!(
925     An,
926     "A 64-bit floating point number",
927     F64,
928     f64,
929     64,
930     8,
931     f64_ext::from_be_bytes,
932     f64_ext::to_be_bytes,
933     f64_ext::from_le_bytes,
934     f64_ext::to_le_bytes,
935     "floating point number",
936     [],
937     [],
938     [],
939     []
940 );
941 
942 macro_rules! module {
943     ($name:ident, $trait:ident, $endianness_str:expr) => {
944         /// Numeric primitives stored in
945         #[doc = $endianness_str]
946         /// byte order.
947         pub mod $name {
948             use super::$trait;
949 
950             module!(@ty U16,  $trait, "16-bit unsigned integer", $endianness_str);
951             module!(@ty U32,  $trait, "32-bit unsigned integer", $endianness_str);
952             module!(@ty U64,  $trait, "64-bit unsigned integer", $endianness_str);
953             module!(@ty U128, $trait, "128-bit unsigned integer", $endianness_str);
954             module!(@ty I16,  $trait, "16-bit signed integer", $endianness_str);
955             module!(@ty I32,  $trait, "32-bit signed integer", $endianness_str);
956             module!(@ty I64,  $trait, "64-bit signed integer", $endianness_str);
957             module!(@ty I128, $trait, "128-bit signed integer", $endianness_str);
958             module!(@ty F32,  $trait, "32-bit floating point number", $endianness_str);
959             module!(@ty F64,  $trait, "64-bit floating point number", $endianness_str);
960         }
961     };
962     (@ty $ty:ident, $trait:ident, $desc_str:expr, $endianness_str:expr) => {
963         /// A
964         #[doc = $desc_str]
965         /// stored in
966         #[doc = $endianness_str]
967         /// byte order.
968         pub type $ty = crate::byteorder::$ty<$trait>;
969     };
970 }
971 
972 module!(big_endian, BigEndian, "big-endian");
973 module!(little_endian, LittleEndian, "little-endian");
974 module!(network_endian, NetworkEndian, "network-endian");
975 module!(native_endian, NativeEndian, "native-endian");
976 
977 #[cfg(any(test, kani))]
978 mod tests {
979     use super::*;
980 
981     #[cfg(not(kani))]
982     mod compatibility {
983         pub(super) use rand::{
984             distributions::{Distribution, Standard},
985             rngs::SmallRng,
986             Rng, SeedableRng,
987         };
988 
989         pub(crate) trait Arbitrary {}
990 
991         impl<T> Arbitrary for T {}
992     }
993 
994     #[cfg(kani)]
995     mod compatibility {
996         pub(crate) use kani::Arbitrary;
997 
998         pub(crate) struct SmallRng;
999 
1000         impl SmallRng {
1001             pub(crate) fn seed_from_u64(_state: u64) -> Self {
1002                 Self
1003             }
1004         }
1005 
1006         pub(crate) trait Rng {
1007             fn sample<T, D: Distribution<T>>(&mut self, _distr: D) -> T
1008             where
1009                 T: Arbitrary,
1010             {
1011                 kani::any()
1012             }
1013         }
1014 
1015         impl Rng for SmallRng {}
1016 
1017         pub(crate) trait Distribution<T> {}
1018         impl<T, U> Distribution<T> for U {}
1019 
1020         pub(crate) struct Standard;
1021     }
1022 
1023     use compatibility::*;
1024 
1025     // A native integer type (u16, i32, etc).
1026     trait Native: Arbitrary + FromBytes + IntoBytes + Immutable + Copy + PartialEq + Debug {
1027         const ZERO: Self;
1028         const MAX_VALUE: Self;
1029 
1030         type Distribution: Distribution<Self>;
1031         const DIST: Self::Distribution;
1032 
1033         fn rand<R: Rng>(rng: &mut R) -> Self {
1034             rng.sample(Self::DIST)
1035         }
1036 
1037         #[cfg_attr(kani, allow(unused))]
1038         fn checked_add(self, rhs: Self) -> Option<Self>;
1039 
1040         #[cfg_attr(kani, allow(unused))]
1041         fn checked_div(self, rhs: Self) -> Option<Self>;
1042 
1043         #[cfg_attr(kani, allow(unused))]
1044         fn checked_mul(self, rhs: Self) -> Option<Self>;
1045 
1046         #[cfg_attr(kani, allow(unused))]
1047         fn checked_rem(self, rhs: Self) -> Option<Self>;
1048 
1049         #[cfg_attr(kani, allow(unused))]
1050         fn checked_sub(self, rhs: Self) -> Option<Self>;
1051 
1052         #[cfg_attr(kani, allow(unused))]
1053         fn checked_shl(self, rhs: Self) -> Option<Self>;
1054 
1055         #[cfg_attr(kani, allow(unused))]
1056         fn checked_shr(self, rhs: Self) -> Option<Self>;
1057 
1058         fn is_nan(self) -> bool;
1059 
1060         /// For `f32` and `f64`, NaN values are not considered equal to
1061         /// themselves. This method is like `assert_eq!`, but it treats NaN
1062         /// values as equal.
1063         fn assert_eq_or_nan(self, other: Self) {
1064             let slf = (!self.is_nan()).then(|| self);
1065             let other = (!other.is_nan()).then(|| other);
1066             assert_eq!(slf, other);
1067         }
1068     }
1069 
1070     trait ByteArray:
1071         FromBytes + IntoBytes + Immutable + Copy + AsRef<[u8]> + AsMut<[u8]> + Debug + Default + Eq
1072     {
1073         /// Invert the order of the bytes in the array.
1074         fn invert(self) -> Self;
1075     }
1076 
1077     trait ByteOrderType:
1078         FromBytes + IntoBytes + Unaligned + Copy + Eq + Debug + Hash + From<Self::Native>
1079     {
1080         type Native: Native;
1081         type ByteArray: ByteArray;
1082 
1083         const ZERO: Self;
1084 
1085         fn new(native: Self::Native) -> Self;
1086         fn get(self) -> Self::Native;
1087         fn set(&mut self, native: Self::Native);
1088         fn from_bytes(bytes: Self::ByteArray) -> Self;
1089         fn into_bytes(self) -> Self::ByteArray;
1090 
1091         /// For `f32` and `f64`, NaN values are not considered equal to
1092         /// themselves. This method is like `assert_eq!`, but it treats NaN
1093         /// values as equal.
1094         fn assert_eq_or_nan(self, other: Self) {
1095             let slf = (!self.get().is_nan()).then(|| self);
1096             let other = (!other.get().is_nan()).then(|| other);
1097             assert_eq!(slf, other);
1098         }
1099     }
1100 
1101     trait ByteOrderTypeUnsigned: ByteOrderType {
1102         const MAX_VALUE: Self;
1103     }
1104 
1105     macro_rules! impl_byte_array {
1106         ($bytes:expr) => {
1107             impl ByteArray for [u8; $bytes] {
1108                 fn invert(mut self) -> [u8; $bytes] {
1109                     self.reverse();
1110                     self
1111                 }
1112             }
1113         };
1114     }
1115 
1116     impl_byte_array!(2);
1117     impl_byte_array!(4);
1118     impl_byte_array!(8);
1119     impl_byte_array!(16);
1120 
1121     macro_rules! impl_byte_order_type_unsigned {
1122         ($name:ident, unsigned) => {
1123             impl<O: ByteOrder> ByteOrderTypeUnsigned for $name<O> {
1124                 const MAX_VALUE: $name<O> = $name::MAX_VALUE;
1125             }
1126         };
1127         ($name:ident, signed) => {};
1128     }
1129 
1130     macro_rules! impl_traits {
1131         ($name:ident, $native:ident, $sign:ident $(, @$float:ident)?) => {
1132             impl Native for $native {
1133                 // For some types, `0 as $native` is required (for example, when
1134                 // `$native` is a floating-point type; `0` is an integer), but
1135                 // for other types, it's a trivial cast. In all cases, Clippy
1136                 // thinks it's dangerous.
1137                 #[allow(trivial_numeric_casts, clippy::as_conversions)]
1138                 const ZERO: $native = 0 as $native;
1139                 const MAX_VALUE: $native = $native::MAX;
1140 
1141                 type Distribution = Standard;
1142                 const DIST: Standard = Standard;
1143 
1144                 impl_traits!(@float_dependent_methods $(@$float)?);
1145             }
1146 
1147             impl<O: ByteOrder> ByteOrderType for $name<O> {
1148                 type Native = $native;
1149                 type ByteArray = [u8; mem::size_of::<$native>()];
1150 
1151                 const ZERO: $name<O> = $name::ZERO;
1152 
1153                 fn new(native: $native) -> $name<O> {
1154                     $name::new(native)
1155                 }
1156 
1157                 fn get(self) -> $native {
1158                     $name::get(self)
1159                 }
1160 
1161                 fn set(&mut self, native: $native) {
1162                     $name::set(self, native)
1163                 }
1164 
1165                 fn from_bytes(bytes: [u8; mem::size_of::<$native>()]) -> $name<O> {
1166                     $name::from(bytes)
1167                 }
1168 
1169                 fn into_bytes(self) -> [u8; mem::size_of::<$native>()] {
1170                     <[u8; mem::size_of::<$native>()]>::from(self)
1171                 }
1172             }
1173 
1174             impl_byte_order_type_unsigned!($name, $sign);
1175         };
1176         (@float_dependent_methods) => {
1177             fn checked_add(self, rhs: Self) -> Option<Self> { self.checked_add(rhs) }
1178             fn checked_div(self, rhs: Self) -> Option<Self> { self.checked_div(rhs) }
1179             fn checked_mul(self, rhs: Self) -> Option<Self> { self.checked_mul(rhs) }
1180             fn checked_rem(self, rhs: Self) -> Option<Self> { self.checked_rem(rhs) }
1181             fn checked_sub(self, rhs: Self) -> Option<Self> { self.checked_sub(rhs) }
1182             fn checked_shl(self, rhs: Self) -> Option<Self> { self.checked_shl(rhs.try_into().unwrap_or(u32::MAX)) }
1183             fn checked_shr(self, rhs: Self) -> Option<Self> { self.checked_shr(rhs.try_into().unwrap_or(u32::MAX)) }
1184             fn is_nan(self) -> bool { false }
1185         };
1186         (@float_dependent_methods @float) => {
1187             fn checked_add(self, rhs: Self) -> Option<Self> { Some(self + rhs) }
1188             fn checked_div(self, rhs: Self) -> Option<Self> { Some(self / rhs) }
1189             fn checked_mul(self, rhs: Self) -> Option<Self> { Some(self * rhs) }
1190             fn checked_rem(self, rhs: Self) -> Option<Self> { Some(self % rhs) }
1191             fn checked_sub(self, rhs: Self) -> Option<Self> { Some(self - rhs) }
1192             fn checked_shl(self, _rhs: Self) -> Option<Self> { unimplemented!() }
1193             fn checked_shr(self, _rhs: Self) -> Option<Self> { unimplemented!() }
1194             fn is_nan(self) -> bool { self.is_nan() }
1195         };
1196     }
1197 
1198     impl_traits!(U16, u16, unsigned);
1199     impl_traits!(U32, u32, unsigned);
1200     impl_traits!(U64, u64, unsigned);
1201     impl_traits!(U128, u128, unsigned);
1202     impl_traits!(Usize, usize, unsigned);
1203     impl_traits!(I16, i16, signed);
1204     impl_traits!(I32, i32, signed);
1205     impl_traits!(I64, i64, signed);
1206     impl_traits!(I128, i128, signed);
1207     impl_traits!(Isize, isize, unsigned);
1208     impl_traits!(F32, f32, signed, @float);
1209     impl_traits!(F64, f64, signed, @float);
1210 
1211     macro_rules! call_for_unsigned_types {
1212         ($fn:ident, $byteorder:ident) => {
1213             $fn::<U16<$byteorder>>();
1214             $fn::<U32<$byteorder>>();
1215             $fn::<U64<$byteorder>>();
1216             $fn::<U128<$byteorder>>();
1217             $fn::<Usize<$byteorder>>();
1218         };
1219     }
1220 
1221     macro_rules! call_for_signed_types {
1222         ($fn:ident, $byteorder:ident) => {
1223             $fn::<I16<$byteorder>>();
1224             $fn::<I32<$byteorder>>();
1225             $fn::<I64<$byteorder>>();
1226             $fn::<I128<$byteorder>>();
1227             $fn::<Isize<$byteorder>>();
1228         };
1229     }
1230 
1231     macro_rules! call_for_float_types {
1232         ($fn:ident, $byteorder:ident) => {
1233             $fn::<F32<$byteorder>>();
1234             $fn::<F64<$byteorder>>();
1235         };
1236     }
1237 
1238     macro_rules! call_for_all_types {
1239         ($fn:ident, $byteorder:ident) => {
1240             call_for_unsigned_types!($fn, $byteorder);
1241             call_for_signed_types!($fn, $byteorder);
1242             call_for_float_types!($fn, $byteorder);
1243         };
1244     }
1245 
1246     #[cfg(target_endian = "big")]
1247     type NonNativeEndian = LittleEndian;
1248     #[cfg(target_endian = "little")]
1249     type NonNativeEndian = BigEndian;
1250 
1251     // We use a `u64` seed so that we can use `SeedableRng::seed_from_u64`.
1252     // `SmallRng`'s `SeedableRng::Seed` differs by platform, so if we wanted to
1253     // call `SeedableRng::from_seed`, which takes a `Seed`, we would need
1254     // conditional compilation by `target_pointer_width`.
1255     const RNG_SEED: u64 = 0x7A03CAE2F32B5B8F;
1256 
1257     const RAND_ITERS: usize = if cfg!(any(miri, kani)) {
1258         // The tests below which use this constant used to take a very long time
1259         // on Miri, which slows down local development and CI jobs. We're not
1260         // using Miri to check for the correctness of our code, but rather its
1261         // soundness, and at least in the context of these particular tests, a
1262         // single loop iteration is just as good for surfacing UB as multiple
1263         // iterations are.
1264         //
1265         // As of the writing of this comment, here's one set of measurements:
1266         //
1267         //   $ # RAND_ITERS == 1
1268         //   $ cargo miri test -- -Z unstable-options --report-time endian
1269         //   test byteorder::tests::test_native_endian ... ok <0.049s>
1270         //   test byteorder::tests::test_non_native_endian ... ok <0.061s>
1271         //
1272         //   $ # RAND_ITERS == 1024
1273         //   $ cargo miri test -- -Z unstable-options --report-time endian
1274         //   test byteorder::tests::test_native_endian ... ok <25.716s>
1275         //   test byteorder::tests::test_non_native_endian ... ok <38.127s>
1276         1
1277     } else {
1278         1024
1279     };
1280 
1281     #[test]
1282     fn test_const_methods() {
1283         use big_endian::*;
1284 
1285         #[rustversion::since(1.61.0)]
1286         const _U: U16 = U16::new(0);
1287         #[rustversion::since(1.61.0)]
1288         const _NATIVE: u16 = _U.get();
1289         const _FROM_BYTES: U16 = U16::from_bytes([0, 1]);
1290         const _BYTES: [u8; 2] = _FROM_BYTES.to_bytes();
1291     }
1292 
1293     #[cfg_attr(test, test)]
1294     #[cfg_attr(kani, kani::proof)]
1295     fn test_zero() {
1296         fn test_zero<T: ByteOrderType>() {
1297             assert_eq!(T::ZERO.get(), T::Native::ZERO);
1298         }
1299 
1300         call_for_all_types!(test_zero, NativeEndian);
1301         call_for_all_types!(test_zero, NonNativeEndian);
1302     }
1303 
1304     #[cfg_attr(test, test)]
1305     #[cfg_attr(kani, kani::proof)]
1306     fn test_max_value() {
1307         fn test_max_value<T: ByteOrderTypeUnsigned>() {
1308             assert_eq!(T::MAX_VALUE.get(), T::Native::MAX_VALUE);
1309         }
1310 
1311         call_for_unsigned_types!(test_max_value, NativeEndian);
1312         call_for_unsigned_types!(test_max_value, NonNativeEndian);
1313     }
1314 
1315     #[cfg_attr(test, test)]
1316     #[cfg_attr(kani, kani::proof)]
1317     fn test_endian() {
1318         fn test<T: ByteOrderType>(invert: bool) {
1319             let mut r = SmallRng::seed_from_u64(RNG_SEED);
1320             for _ in 0..RAND_ITERS {
1321                 let native = T::Native::rand(&mut r);
1322                 let mut bytes = T::ByteArray::default();
1323                 bytes.as_mut_bytes().copy_from_slice(native.as_bytes());
1324                 if invert {
1325                     bytes = bytes.invert();
1326                 }
1327                 let mut from_native = T::new(native);
1328                 let from_bytes = T::from_bytes(bytes);
1329 
1330                 from_native.assert_eq_or_nan(from_bytes);
1331                 from_native.get().assert_eq_or_nan(native);
1332                 from_bytes.get().assert_eq_or_nan(native);
1333 
1334                 assert_eq!(from_native.into_bytes(), bytes);
1335                 assert_eq!(from_bytes.into_bytes(), bytes);
1336 
1337                 let updated = T::Native::rand(&mut r);
1338                 from_native.set(updated);
1339                 from_native.get().assert_eq_or_nan(updated);
1340             }
1341         }
1342 
1343         fn test_native<T: ByteOrderType>() {
1344             test::<T>(false);
1345         }
1346 
1347         fn test_non_native<T: ByteOrderType>() {
1348             test::<T>(true);
1349         }
1350 
1351         call_for_all_types!(test_native, NativeEndian);
1352         call_for_all_types!(test_non_native, NonNativeEndian);
1353     }
1354 
1355     #[test]
1356     fn test_ops_impls() {
1357         // Test implementations of traits in `core::ops`. Some of these are
1358         // fairly banal, but some are optimized to perform the operation without
1359         // swapping byte order (namely, bit-wise operations which are identical
1360         // regardless of byte order). These are important to test, and while
1361         // we're testing those anyway, it's trivial to test all of the impls.
1362 
1363         fn test<T, FTT, FTN, FNT, FNN, FNNChecked, FATT, FATN, FANT>(
1364             op_t_t: FTT,
1365             op_t_n: FTN,
1366             op_n_t: FNT,
1367             op_n_n: FNN,
1368             op_n_n_checked: Option<FNNChecked>,
1369             op_assign: Option<(FATT, FATN, FANT)>,
1370         ) where
1371             T: ByteOrderType,
1372             FTT: Fn(T, T) -> T,
1373             FTN: Fn(T, T::Native) -> T,
1374             FNT: Fn(T::Native, T) -> T,
1375             FNN: Fn(T::Native, T::Native) -> T::Native,
1376             FNNChecked: Fn(T::Native, T::Native) -> Option<T::Native>,
1377             FATT: Fn(&mut T, T),
1378             FATN: Fn(&mut T, T::Native),
1379             FANT: Fn(&mut T::Native, T),
1380         {
1381             let mut r = SmallRng::seed_from_u64(RNG_SEED);
1382             for _ in 0..RAND_ITERS {
1383                 let n0 = T::Native::rand(&mut r);
1384                 let n1 = T::Native::rand(&mut r);
1385                 let t0 = T::new(n0);
1386                 let t1 = T::new(n1);
1387 
1388                 // If this operation would overflow/underflow, skip it rather
1389                 // than attempt to catch and recover from panics.
1390                 if matches!(&op_n_n_checked, Some(checked) if checked(n0, n1).is_none()) {
1391                     continue;
1392                 }
1393 
1394                 let t_t_res = op_t_t(t0, t1);
1395                 let t_n_res = op_t_n(t0, n1);
1396                 let n_t_res = op_n_t(n0, t1);
1397                 let n_n_res = op_n_n(n0, n1);
1398 
1399                 // For `f32` and `f64`, NaN values are not considered equal to
1400                 // themselves. We store `Option<f32>`/`Option<f64>` and store
1401                 // NaN as `None` so they can still be compared.
1402                 let val_or_none = |t: T| (!T::Native::is_nan(t.get())).then(|| t.get());
1403                 let t_t_res = val_or_none(t_t_res);
1404                 let t_n_res = val_or_none(t_n_res);
1405                 let n_t_res = val_or_none(n_t_res);
1406                 let n_n_res = (!T::Native::is_nan(n_n_res)).then(|| n_n_res);
1407                 assert_eq!(t_t_res, n_n_res);
1408                 assert_eq!(t_n_res, n_n_res);
1409                 assert_eq!(n_t_res, n_n_res);
1410 
1411                 if let Some((op_assign_t_t, op_assign_t_n, op_assign_n_t)) = &op_assign {
1412                     let mut t_t_res = t0;
1413                     op_assign_t_t(&mut t_t_res, t1);
1414                     let mut t_n_res = t0;
1415                     op_assign_t_n(&mut t_n_res, n1);
1416                     let mut n_t_res = n0;
1417                     op_assign_n_t(&mut n_t_res, t1);
1418 
1419                     // For `f32` and `f64`, NaN values are not considered equal to
1420                     // themselves. We store `Option<f32>`/`Option<f64>` and store
1421                     // NaN as `None` so they can still be compared.
1422                     let t_t_res = val_or_none(t_t_res);
1423                     let t_n_res = val_or_none(t_n_res);
1424                     let n_t_res = (!T::Native::is_nan(n_t_res)).then(|| n_t_res);
1425                     assert_eq!(t_t_res, n_n_res);
1426                     assert_eq!(t_n_res, n_n_res);
1427                     assert_eq!(n_t_res, n_n_res);
1428                 }
1429             }
1430         }
1431 
1432         macro_rules! test {
1433             (
1434                 @binary
1435                 $trait:ident,
1436                 $method:ident $([$checked_method:ident])?,
1437                 $trait_assign:ident,
1438                 $method_assign:ident,
1439                 $($call_for_macros:ident),*
1440             ) => {{
1441                 fn t<T>()
1442                 where
1443                     T: ByteOrderType,
1444                     T: core::ops::$trait<T, Output = T>,
1445                     T: core::ops::$trait<T::Native, Output = T>,
1446                     T::Native: core::ops::$trait<T, Output = T>,
1447                     T::Native: core::ops::$trait<T::Native, Output = T::Native>,
1448 
1449                     T: core::ops::$trait_assign<T>,
1450                     T: core::ops::$trait_assign<T::Native>,
1451                     T::Native: core::ops::$trait_assign<T>,
1452                     T::Native: core::ops::$trait_assign<T::Native>,
1453                 {
1454                     test::<T, _, _, _, _, _, _, _, _>(
1455                         core::ops::$trait::$method,
1456                         core::ops::$trait::$method,
1457                         core::ops::$trait::$method,
1458                         core::ops::$trait::$method,
1459                         {
1460                             #[allow(unused_mut, unused_assignments)]
1461                             let mut op_native_checked = None::<fn(T::Native, T::Native) -> Option<T::Native>>;
1462                             $(
1463                                 op_native_checked = Some(T::Native::$checked_method);
1464                             )?
1465                             op_native_checked
1466                         },
1467                         Some((
1468                             <T as core::ops::$trait_assign<T>>::$method_assign,
1469                             <T as core::ops::$trait_assign::<T::Native>>::$method_assign,
1470                             <T::Native as core::ops::$trait_assign::<T>>::$method_assign
1471                         )),
1472                     );
1473                 }
1474 
1475                 $(
1476                     $call_for_macros!(t, NativeEndian);
1477                     $call_for_macros!(t, NonNativeEndian);
1478                 )*
1479             }};
1480             (
1481                 @unary
1482                 $trait:ident,
1483                 $method:ident,
1484                 $($call_for_macros:ident),*
1485             ) => {{
1486                 fn t<T>()
1487                 where
1488                     T: ByteOrderType,
1489                     T: core::ops::$trait<Output = T>,
1490                     T::Native: core::ops::$trait<Output = T::Native>,
1491                 {
1492                     test::<T, _, _, _, _, _, _, _, _>(
1493                         |slf, _rhs| core::ops::$trait::$method(slf),
1494                         |slf, _rhs| core::ops::$trait::$method(slf),
1495                         |slf, _rhs| core::ops::$trait::$method(slf).into(),
1496                         |slf, _rhs| core::ops::$trait::$method(slf),
1497                         None::<fn(T::Native, T::Native) -> Option<T::Native>>,
1498                         None::<(fn(&mut T, T), fn(&mut T, T::Native), fn(&mut T::Native, T))>,
1499                     );
1500                 }
1501 
1502                 $(
1503                     $call_for_macros!(t, NativeEndian);
1504                     $call_for_macros!(t, NonNativeEndian);
1505                 )*
1506             }};
1507         }
1508 
1509         test!(@binary Add, add[checked_add], AddAssign, add_assign, call_for_all_types);
1510         test!(@binary Div, div[checked_div], DivAssign, div_assign, call_for_all_types);
1511         test!(@binary Mul, mul[checked_mul], MulAssign, mul_assign, call_for_all_types);
1512         test!(@binary Rem, rem[checked_rem], RemAssign, rem_assign, call_for_all_types);
1513         test!(@binary Sub, sub[checked_sub], SubAssign, sub_assign, call_for_all_types);
1514 
1515         test!(@binary BitAnd, bitand, BitAndAssign, bitand_assign, call_for_unsigned_types, call_for_signed_types);
1516         test!(@binary BitOr, bitor, BitOrAssign, bitor_assign, call_for_unsigned_types, call_for_signed_types);
1517         test!(@binary BitXor, bitxor, BitXorAssign, bitxor_assign, call_for_unsigned_types, call_for_signed_types);
1518         test!(@binary Shl, shl[checked_shl], ShlAssign, shl_assign, call_for_unsigned_types, call_for_signed_types);
1519         test!(@binary Shr, shr[checked_shr], ShrAssign, shr_assign, call_for_unsigned_types, call_for_signed_types);
1520 
1521         test!(@unary Not, not, call_for_signed_types, call_for_unsigned_types);
1522         test!(@unary Neg, neg, call_for_signed_types, call_for_float_types);
1523     }
1524 
1525     #[test]
1526     fn test_debug_impl() {
1527         // Ensure that Debug applies format options to the inner value.
1528         let val = U16::<LE>::new(10);
1529         assert_eq!(format!("{:?}", val), "U16(10)");
1530         assert_eq!(format!("{:03?}", val), "U16(010)");
1531         assert_eq!(format!("{:x?}", val), "U16(a)");
1532     }
1533 
1534     #[test]
1535     fn test_byteorder_traits_coverage() {
1536         let val_be = U16::<BigEndian>::from_bytes([0, 1]);
1537         let val_le = U16::<LittleEndian>::from_bytes([1, 0]);
1538 
1539         assert_eq!(val_be.get(), 1);
1540         assert_eq!(val_le.get(), 1);
1541 
1542         // Debug
1543         assert_eq!(format!("{:?}", val_be), "U16(1)");
1544         assert_eq!(format!("{:?}", val_le), "U16(1)");
1545 
1546         // PartialOrd, Ord with same type
1547         assert!(val_be >= val_be);
1548         assert!(val_be <= val_be);
1549         assert_eq!(val_be.cmp(&val_be), core::cmp::Ordering::Equal);
1550 
1551         // PartialOrd with native
1552         assert!(val_be == 1u16);
1553         assert!(val_be >= 1u16);
1554 
1555         // Default
1556         let default_be: U16<BigEndian> = Default::default();
1557         assert_eq!(default_be.get(), 0);
1558 
1559         // I16
1560         let val_be_i16 = I16::<BigEndian>::from_bytes([0, 1]);
1561         assert_eq!(val_be_i16.get(), 1);
1562         assert_eq!(format!("{:?}", val_be_i16), "I16(1)");
1563         assert_eq!(val_be_i16.cmp(&val_be_i16), core::cmp::Ordering::Equal);
1564     }
1565 }
1566