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