zerocopy/
byteorder.rs

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