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