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