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