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