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