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