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