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