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