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