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