1 // Copyright 2019 The Fuchsia Authors 2 // 3 // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0 4 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. 6 // This file may not be copied, modified, or distributed except according to 7 // those terms. 8 9 //! Byte order-aware numeric primitives. 10 //! 11 //! This module contains equivalents of the native multi-byte integer types with 12 //! no alignment requirement and supporting byte order conversions. 13 //! 14 //! For each native multi-byte integer type - `u16`, `i16`, `u32`, etc - and 15 //! floating point type - `f32` and `f64` - an equivalent type is defined by 16 //! this module - [`U16`], [`I16`], [`U32`], [`F64`], etc. Unlike their native 17 //! counterparts, these types have alignment 1, and take a type parameter 18 //! specifying the byte order in which the bytes are stored in memory. Each type 19 //! implements the [`FromBytes`], [`AsBytes`], and [`Unaligned`] traits. 20 //! 21 //! These two properties, taken together, make these types useful for defining 22 //! data structures whose memory layout matches a wire format such as that of a 23 //! network protocol or a file format. Such formats often have multi-byte values 24 //! at offsets that do not respect the alignment requirements of the equivalent 25 //! native types, and stored in a byte order not necessarily the same as that of 26 //! the target platform. 27 //! 28 //! Type aliases are provided for common byte orders in the [`big_endian`], 29 //! [`little_endian`], [`network_endian`], and [`native_endian`] submodules. 30 //! 31 //! # Example 32 //! 33 //! One use of these types is for representing network packet formats, such as 34 //! UDP: 35 //! 36 //! ```rust,edition2021 37 //! # #[cfg(feature = "derive")] { // This example uses derives, and won't compile without them 38 //! use zerocopy::{AsBytes, ByteSlice, FromBytes, FromZeroes, Ref, Unaligned}; 39 //! use zerocopy::byteorder::network_endian::U16; 40 //! 41 //! #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] 42 //! #[repr(C)] 43 //! struct UdpHeader { 44 //! src_port: U16, 45 //! dst_port: U16, 46 //! length: U16, 47 //! checksum: U16, 48 //! } 49 //! 50 //! struct UdpPacket<B: ByteSlice> { 51 //! header: Ref<B, UdpHeader>, 52 //! body: B, 53 //! } 54 //! 55 //! impl<B: ByteSlice> UdpPacket<B> { 56 //! fn parse(bytes: B) -> Option<UdpPacket<B>> { 57 //! let (header, body) = Ref::new_from_prefix(bytes)?; 58 //! Some(UdpPacket { header, body }) 59 //! } 60 //! 61 //! fn src_port(&self) -> u16 { 62 //! self.header.src_port.get() 63 //! } 64 //! 65 //! // more getters... 66 //! } 67 //! # } 68 //! ``` 69 70 use core::{ 71 convert::{TryFrom, TryInto}, 72 fmt::{self, Binary, Debug, Display, Formatter, LowerHex, Octal, UpperHex}, 73 marker::PhantomData, 74 num::TryFromIntError, 75 }; 76 77 // We don't reexport `WriteBytesExt` or `ReadBytesExt` because those are only 78 // available with the `std` feature enabled, and zerocopy is `no_std` by 79 // default. 80 pub use ::byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian, NetworkEndian, BE, LE}; 81 82 use super::*; 83 84 macro_rules! impl_fmt_trait { 85 ($name:ident, $native:ident, $trait:ident) => { 86 impl<O: ByteOrder> $trait for $name<O> { 87 #[inline(always)] 88 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 89 $trait::fmt(&self.get(), f) 90 } 91 } 92 }; 93 } 94 95 macro_rules! impl_fmt_traits { 96 ($name:ident, $native:ident, "floating point number") => { 97 impl_fmt_trait!($name, $native, Display); 98 }; 99 ($name:ident, $native:ident, "unsigned integer") => { 100 impl_fmt_traits!($name, $native, @all_types); 101 }; 102 ($name:ident, $native:ident, "signed integer") => { 103 impl_fmt_traits!($name, $native, @all_types); 104 }; 105 ($name:ident, $native:ident, @all_types) => { 106 impl_fmt_trait!($name, $native, Display); 107 impl_fmt_trait!($name, $native, Octal); 108 impl_fmt_trait!($name, $native, LowerHex); 109 impl_fmt_trait!($name, $native, UpperHex); 110 impl_fmt_trait!($name, $native, Binary); 111 }; 112 } 113 114 macro_rules! impl_ops_traits { 115 ($name:ident, $native:ident, "floating point number") => { 116 impl_ops_traits!($name, $native, @all_types); 117 impl_ops_traits!($name, $native, @signed_integer_floating_point); 118 }; 119 ($name:ident, $native:ident, "unsigned integer") => { 120 impl_ops_traits!($name, $native, @signed_unsigned_integer); 121 impl_ops_traits!($name, $native, @all_types); 122 }; 123 ($name:ident, $native:ident, "signed integer") => { 124 impl_ops_traits!($name, $native, @signed_unsigned_integer); 125 impl_ops_traits!($name, $native, @signed_integer_floating_point); 126 impl_ops_traits!($name, $native, @all_types); 127 }; 128 ($name:ident, $native:ident, @signed_unsigned_integer) => { 129 impl_ops_traits!(@without_byteorder_swap $name, $native, BitAnd, bitand, BitAndAssign, bitand_assign); 130 impl_ops_traits!(@without_byteorder_swap $name, $native, BitOr, bitor, BitOrAssign, bitor_assign); 131 impl_ops_traits!(@without_byteorder_swap $name, $native, BitXor, bitxor, BitXorAssign, bitxor_assign); 132 impl_ops_traits!(@with_byteorder_swap $name, $native, Shl, shl, ShlAssign, shl_assign); 133 impl_ops_traits!(@with_byteorder_swap $name, $native, Shr, shr, ShrAssign, shr_assign); 134 135 impl<O> core::ops::Not for $name<O> { 136 type Output = $name<O>; 137 138 #[inline(always)] 139 fn not(self) -> $name<O> { 140 let self_native = $native::from_ne_bytes(self.0); 141 $name((!self_native).to_ne_bytes(), PhantomData) 142 } 143 } 144 }; 145 ($name:ident, $native:ident, @signed_integer_floating_point) => { 146 impl<O: ByteOrder> core::ops::Neg for $name<O> { 147 type Output = $name<O>; 148 149 #[inline(always)] 150 fn neg(self) -> $name<O> { 151 let self_native: $native = self.get(); 152 #[allow(clippy::arithmetic_side_effects)] 153 $name::<O>::new(-self_native) 154 } 155 } 156 }; 157 ($name:ident, $native:ident, @all_types) => { 158 impl_ops_traits!(@with_byteorder_swap $name, $native, Add, add, AddAssign, add_assign); 159 impl_ops_traits!(@with_byteorder_swap $name, $native, Div, div, DivAssign, div_assign); 160 impl_ops_traits!(@with_byteorder_swap $name, $native, Mul, mul, MulAssign, mul_assign); 161 impl_ops_traits!(@with_byteorder_swap $name, $native, Rem, rem, RemAssign, rem_assign); 162 impl_ops_traits!(@with_byteorder_swap $name, $native, Sub, sub, SubAssign, sub_assign); 163 }; 164 (@with_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => { 165 impl<O: ByteOrder> core::ops::$trait for $name<O> { 166 type Output = $name<O>; 167 168 #[inline(always)] 169 fn $method(self, rhs: $name<O>) -> $name<O> { 170 let self_native: $native = self.get(); 171 let rhs_native: $native = rhs.get(); 172 let result_native = core::ops::$trait::$method(self_native, rhs_native); 173 $name::<O>::new(result_native) 174 } 175 } 176 177 impl<O: ByteOrder> core::ops::$trait_assign for $name<O> { 178 #[inline(always)] 179 fn $method_assign(&mut self, rhs: $name<O>) { 180 *self = core::ops::$trait::$method(*self, rhs); 181 } 182 } 183 }; 184 // Implement traits in terms of the same trait on the native type, but 185 // without performing a byte order swap. This only works for bitwise 186 // operations like `&`, `|`, etc. 187 (@without_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => { 188 impl<O: ByteOrder> core::ops::$trait for $name<O> { 189 type Output = $name<O>; 190 191 #[inline(always)] 192 fn $method(self, rhs: $name<O>) -> $name<O> { 193 let self_native = $native::from_ne_bytes(self.0); 194 let rhs_native = $native::from_ne_bytes(rhs.0); 195 let result_native = core::ops::$trait::$method(self_native, rhs_native); 196 $name(result_native.to_ne_bytes(), PhantomData) 197 } 198 } 199 200 impl<O: ByteOrder> core::ops::$trait_assign for $name<O> { 201 #[inline(always)] 202 fn $method_assign(&mut self, rhs: $name<O>) { 203 *self = core::ops::$trait::$method(*self, rhs); 204 } 205 } 206 }; 207 } 208 209 macro_rules! doc_comment { 210 ($x:expr, $($tt:tt)*) => { 211 #[doc = $x] 212 $($tt)* 213 }; 214 } 215 216 macro_rules! define_max_value_constant { 217 ($name:ident, $bytes:expr, "unsigned integer") => { 218 /// The maximum value. 219 /// 220 /// This constant should be preferred to constructing a new value using 221 /// `new`, as `new` may perform an endianness swap depending on the 222 /// endianness `O` and the endianness of the platform. 223 pub const MAX_VALUE: $name<O> = $name([0xFFu8; $bytes], PhantomData); 224 }; 225 // We don't provide maximum and minimum value constants for signed values 226 // and floats because there's no way to do it generically - it would require 227 // a different value depending on the value of the `ByteOrder` type 228 // parameter. Currently, one workaround would be to provide implementations 229 // for concrete implementations of that trait. In the long term, if we are 230 // ever able to make the `new` constructor a const fn, we could use that 231 // instead. 232 ($name:ident, $bytes:expr, "signed integer") => {}; 233 ($name:ident, $bytes:expr, "floating point number") => {}; 234 } 235 236 macro_rules! define_type { 237 ($article:ident, 238 $name:ident, 239 $native:ident, 240 $bits:expr, 241 $bytes:expr, 242 $read_method:ident, 243 $write_method:ident, 244 $number_kind:tt, 245 [$($larger_native:ty),*], 246 [$($larger_native_try:ty),*], 247 [$($larger_byteorder:ident),*], 248 [$($larger_byteorder_try:ident),*]) => { 249 doc_comment! { 250 concat!("A ", stringify!($bits), "-bit ", $number_kind, 251 " stored in a given byte order. 252 253 `", stringify!($name), "` is like the native `", stringify!($native), "` type with 254 two major differences: First, it has no alignment requirement (its alignment is 1). 255 Second, the endianness of its memory layout is given by the type parameter `O`, 256 which can be any type which implements [`ByteOrder`]. In particular, this refers 257 to [`BigEndian`], [`LittleEndian`], [`NativeEndian`], and [`NetworkEndian`]. 258 259 ", stringify!($article), " `", stringify!($name), "` can be constructed using 260 the [`new`] method, and its contained value can be obtained as a native 261 `",stringify!($native), "` using the [`get`] method, or updated in place with 262 the [`set`] method. In all cases, if the endianness `O` is not the same as the 263 endianness of the current platform, an endianness swap will be performed in 264 order to uphold the invariants that a) the layout of `", stringify!($name), "` 265 has endianness `O` and that, b) the layout of `", stringify!($native), "` has 266 the platform's native endianness. 267 268 `", stringify!($name), "` implements [`FromBytes`], [`AsBytes`], and [`Unaligned`], 269 making it useful for parsing and serialization. See the module documentation for an 270 example of how it can be used for parsing UDP packets. 271 272 [`new`]: crate::byteorder::", stringify!($name), "::new 273 [`get`]: crate::byteorder::", stringify!($name), "::get 274 [`set`]: crate::byteorder::", stringify!($name), "::set 275 [`FromBytes`]: crate::FromBytes 276 [`AsBytes`]: crate::AsBytes 277 [`Unaligned`]: crate::Unaligned"), 278 #[derive(Copy, Clone, Eq, PartialEq, Hash)] 279 #[cfg_attr(any(feature = "derive", test), derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned))] 280 #[repr(transparent)] 281 pub struct $name<O>([u8; $bytes], PhantomData<O>); 282 } 283 284 #[cfg(not(any(feature = "derive", test)))] 285 impl_known_layout!(O => $name<O>); 286 287 safety_comment! { 288 /// SAFETY: 289 /// `$name<O>` is `repr(transparent)`, and so it has the same layout 290 /// as its only non-zero field, which is a `u8` array. `u8` arrays 291 /// are `FromZeroes`, `FromBytes`, `AsBytes`, and `Unaligned`. 292 impl_or_verify!(O => FromZeroes for $name<O>); 293 impl_or_verify!(O => FromBytes for $name<O>); 294 impl_or_verify!(O => AsBytes for $name<O>); 295 impl_or_verify!(O => Unaligned for $name<O>); 296 } 297 298 impl<O> Default for $name<O> { 299 #[inline(always)] 300 fn default() -> $name<O> { 301 $name::ZERO 302 } 303 } 304 305 impl<O> $name<O> { 306 /// The value zero. 307 /// 308 /// This constant should be preferred to constructing a new value 309 /// using `new`, as `new` may perform an endianness swap depending 310 /// on the endianness and platform. 311 pub const ZERO: $name<O> = $name([0u8; $bytes], PhantomData); 312 313 define_max_value_constant!($name, $bytes, $number_kind); 314 315 /// Constructs a new value from bytes which are already in the 316 /// endianness `O`. 317 #[inline(always)] 318 pub const fn from_bytes(bytes: [u8; $bytes]) -> $name<O> { 319 $name(bytes, PhantomData) 320 } 321 } 322 323 impl<O: ByteOrder> $name<O> { 324 // TODO(joshlf): Make these const fns if the `ByteOrder` methods 325 // ever become const fns. 326 327 /// Constructs a new value, possibly performing an endianness swap 328 /// to guarantee that the returned value has endianness `O`. 329 #[inline(always)] 330 pub fn new(n: $native) -> $name<O> { 331 let mut out = $name::default(); 332 O::$write_method(&mut out.0[..], n); 333 out 334 } 335 336 /// Returns the value as a primitive type, possibly performing an 337 /// endianness swap to guarantee that the return value has the 338 /// endianness of the native platform. 339 #[inline(always)] 340 pub fn get(self) -> $native { 341 O::$read_method(&self.0[..]) 342 } 343 344 /// Updates the value in place as a primitive type, possibly 345 /// performing an endianness swap to guarantee that the stored value 346 /// has the endianness `O`. 347 #[inline(always)] 348 pub fn set(&mut self, n: $native) { 349 O::$write_method(&mut self.0[..], n); 350 } 351 } 352 353 // The reasoning behind which traits to implement here is to only 354 // implement traits which won't cause inference issues. Notably, 355 // comparison traits like PartialEq and PartialOrd tend to cause 356 // inference issues. 357 358 impl<O: ByteOrder> From<$name<O>> for [u8; $bytes] { 359 #[inline(always)] 360 fn from(x: $name<O>) -> [u8; $bytes] { 361 x.0 362 } 363 } 364 365 impl<O: ByteOrder> From<[u8; $bytes]> for $name<O> { 366 #[inline(always)] 367 fn from(bytes: [u8; $bytes]) -> $name<O> { 368 $name(bytes, PhantomData) 369 } 370 } 371 372 impl<O: ByteOrder> From<$name<O>> for $native { 373 #[inline(always)] 374 fn from(x: $name<O>) -> $native { 375 x.get() 376 } 377 } 378 379 impl<O: ByteOrder> From<$native> for $name<O> { 380 #[inline(always)] 381 fn from(x: $native) -> $name<O> { 382 $name::new(x) 383 } 384 } 385 386 $( 387 impl<O: ByteOrder> From<$name<O>> for $larger_native { 388 #[inline(always)] 389 fn from(x: $name<O>) -> $larger_native { 390 x.get().into() 391 } 392 } 393 )* 394 395 $( 396 impl<O: ByteOrder> TryFrom<$larger_native_try> for $name<O> { 397 type Error = TryFromIntError; 398 #[inline(always)] 399 fn try_from(x: $larger_native_try) -> Result<$name<O>, TryFromIntError> { 400 $native::try_from(x).map($name::new) 401 } 402 } 403 )* 404 405 $( 406 impl<O: ByteOrder, P: ByteOrder> From<$name<O>> for $larger_byteorder<P> { 407 #[inline(always)] 408 fn from(x: $name<O>) -> $larger_byteorder<P> { 409 $larger_byteorder::new(x.get().into()) 410 } 411 } 412 )* 413 414 $( 415 impl<O: ByteOrder, P: ByteOrder> TryFrom<$larger_byteorder_try<P>> for $name<O> { 416 type Error = TryFromIntError; 417 #[inline(always)] 418 fn try_from(x: $larger_byteorder_try<P>) -> Result<$name<O>, TryFromIntError> { 419 x.get().try_into().map($name::new) 420 } 421 } 422 )* 423 424 impl<O: ByteOrder> AsRef<[u8; $bytes]> for $name<O> { 425 #[inline(always)] 426 fn as_ref(&self) -> &[u8; $bytes] { 427 &self.0 428 } 429 } 430 431 impl<O: ByteOrder> AsMut<[u8; $bytes]> for $name<O> { 432 #[inline(always)] 433 fn as_mut(&mut self) -> &mut [u8; $bytes] { 434 &mut self.0 435 } 436 } 437 438 impl<O: ByteOrder> PartialEq<$name<O>> for [u8; $bytes] { 439 #[inline(always)] 440 fn eq(&self, other: &$name<O>) -> bool { 441 self.eq(&other.0) 442 } 443 } 444 445 impl<O: ByteOrder> PartialEq<[u8; $bytes]> for $name<O> { 446 #[inline(always)] 447 fn eq(&self, other: &[u8; $bytes]) -> bool { 448 self.0.eq(other) 449 } 450 } 451 452 impl_fmt_traits!($name, $native, $number_kind); 453 impl_ops_traits!($name, $native, $number_kind); 454 455 impl<O: ByteOrder> Debug for $name<O> { 456 #[inline] 457 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 458 // This results in a format like "U16(42)". 459 f.debug_tuple(stringify!($name)).field(&self.get()).finish() 460 } 461 } 462 }; 463 } 464 465 define_type!( 466 A, 467 U16, 468 u16, 469 16, 470 2, 471 read_u16, 472 write_u16, 473 "unsigned integer", 474 [u32, u64, u128, usize], 475 [u32, u64, u128, usize], 476 [U32, U64, U128], 477 [U32, U64, U128] 478 ); 479 define_type!( 480 A, 481 U32, 482 u32, 483 32, 484 4, 485 read_u32, 486 write_u32, 487 "unsigned integer", 488 [u64, u128], 489 [u64, u128], 490 [U64, U128], 491 [U64, U128] 492 ); 493 define_type!( 494 A, 495 U64, 496 u64, 497 64, 498 8, 499 read_u64, 500 write_u64, 501 "unsigned integer", 502 [u128], 503 [u128], 504 [U128], 505 [U128] 506 ); 507 define_type!(A, U128, u128, 128, 16, read_u128, write_u128, "unsigned integer", [], [], [], []); 508 define_type!( 509 An, 510 I16, 511 i16, 512 16, 513 2, 514 read_i16, 515 write_i16, 516 "signed integer", 517 [i32, i64, i128, isize], 518 [i32, i64, i128, isize], 519 [I32, I64, I128], 520 [I32, I64, I128] 521 ); 522 define_type!( 523 An, 524 I32, 525 i32, 526 32, 527 4, 528 read_i32, 529 write_i32, 530 "signed integer", 531 [i64, i128], 532 [i64, i128], 533 [I64, I128], 534 [I64, I128] 535 ); 536 define_type!( 537 An, 538 I64, 539 i64, 540 64, 541 8, 542 read_i64, 543 write_i64, 544 "signed integer", 545 [i128], 546 [i128], 547 [I128], 548 [I128] 549 ); 550 define_type!(An, I128, i128, 128, 16, read_i128, write_i128, "signed integer", [], [], [], []); 551 define_type!( 552 An, 553 F32, 554 f32, 555 32, 556 4, 557 read_f32, 558 write_f32, 559 "floating point number", 560 [f64], 561 [], 562 [F64], 563 [] 564 ); 565 define_type!(An, F64, f64, 64, 8, read_f64, write_f64, "floating point number", [], [], [], []); 566 567 macro_rules! module { 568 ($name:ident, $trait:ident, $endianness_str:expr) => { 569 /// Numeric primitives stored in 570 #[doc = $endianness_str] 571 /// byte order. 572 pub mod $name { 573 use byteorder::$trait; 574 575 module!(@ty U16, $trait, "16-bit unsigned integer", $endianness_str); 576 module!(@ty U32, $trait, "32-bit unsigned integer", $endianness_str); 577 module!(@ty U64, $trait, "64-bit unsigned integer", $endianness_str); 578 module!(@ty U128, $trait, "128-bit unsigned integer", $endianness_str); 579 module!(@ty I16, $trait, "16-bit signed integer", $endianness_str); 580 module!(@ty I32, $trait, "32-bit signed integer", $endianness_str); 581 module!(@ty I64, $trait, "64-bit signed integer", $endianness_str); 582 module!(@ty I128, $trait, "128-bit signed integer", $endianness_str); 583 module!(@ty F32, $trait, "32-bit floating point number", $endianness_str); 584 module!(@ty F64, $trait, "64-bit floating point number", $endianness_str); 585 } 586 }; 587 (@ty $ty:ident, $trait:ident, $desc_str:expr, $endianness_str:expr) => { 588 /// A 589 #[doc = $desc_str] 590 /// stored in 591 #[doc = $endianness_str] 592 /// byte order. 593 pub type $ty = crate::byteorder::$ty<$trait>; 594 }; 595 } 596 597 module!(big_endian, BigEndian, "big-endian"); 598 module!(little_endian, LittleEndian, "little-endian"); 599 module!(network_endian, NetworkEndian, "network-endian"); 600 module!(native_endian, NativeEndian, "native-endian"); 601 602 #[cfg(any(test, kani))] 603 mod tests { 604 use ::byteorder::NativeEndian; 605 606 use { 607 super::*, 608 crate::{AsBytes, FromBytes, Unaligned}, 609 }; 610 611 #[cfg(not(kani))] 612 mod compatibility { 613 pub(super) use rand::{ 614 distributions::{Distribution, Standard}, 615 rngs::SmallRng, 616 Rng, SeedableRng, 617 }; 618 619 pub(crate) trait Arbitrary {} 620 621 impl<T> Arbitrary for T {} 622 } 623 624 #[cfg(kani)] 625 mod compatibility { 626 pub(crate) use kani::Arbitrary; 627 628 pub(crate) struct SmallRng; 629 630 impl SmallRng { seed_from_u64(_state: u64) -> Self631 pub(crate) fn seed_from_u64(_state: u64) -> Self { 632 Self 633 } 634 } 635 636 pub(crate) trait Rng { sample<T, D: Distribution<T>>(&mut self, _distr: D) -> T where T: Arbitrary,637 fn sample<T, D: Distribution<T>>(&mut self, _distr: D) -> T 638 where 639 T: Arbitrary, 640 { 641 kani::any() 642 } 643 } 644 645 impl Rng for SmallRng {} 646 647 pub(crate) trait Distribution<T> {} 648 impl<T, U> Distribution<T> for U {} 649 650 pub(crate) struct Standard; 651 } 652 653 use compatibility::*; 654 655 // A native integer type (u16, i32, etc). 656 #[cfg_attr(kani, allow(dead_code))] 657 trait Native: Arbitrary + FromBytes + AsBytes + Copy + PartialEq + Debug { 658 const ZERO: Self; 659 const MAX_VALUE: Self; 660 661 type Distribution: Distribution<Self>; 662 const DIST: Self::Distribution; 663 rand<R: Rng>(rng: &mut R) -> Self664 fn rand<R: Rng>(rng: &mut R) -> Self { 665 rng.sample(Self::DIST) 666 } 667 checked_add(self, rhs: Self) -> Option<Self>668 fn checked_add(self, rhs: Self) -> Option<Self>; checked_div(self, rhs: Self) -> Option<Self>669 fn checked_div(self, rhs: Self) -> Option<Self>; checked_mul(self, rhs: Self) -> Option<Self>670 fn checked_mul(self, rhs: Self) -> Option<Self>; checked_rem(self, rhs: Self) -> Option<Self>671 fn checked_rem(self, rhs: Self) -> Option<Self>; checked_sub(self, rhs: Self) -> Option<Self>672 fn checked_sub(self, rhs: Self) -> Option<Self>; checked_shl(self, rhs: Self) -> Option<Self>673 fn checked_shl(self, rhs: Self) -> Option<Self>; checked_shr(self, rhs: Self) -> Option<Self>674 fn checked_shr(self, rhs: Self) -> Option<Self>; 675 is_nan(self) -> bool676 fn is_nan(self) -> bool; 677 678 /// For `f32` and `f64`, NaN values are not considered equal to 679 /// themselves. This method is like `assert_eq!`, but it treats NaN 680 /// values as equal. assert_eq_or_nan(self, other: Self)681 fn assert_eq_or_nan(self, other: Self) { 682 let slf = (!self.is_nan()).then(|| self); 683 let other = (!other.is_nan()).then(|| other); 684 assert_eq!(slf, other); 685 } 686 } 687 688 trait ByteArray: 689 FromBytes + AsBytes + Copy + AsRef<[u8]> + AsMut<[u8]> + Debug + Default + Eq 690 { 691 /// Invert the order of the bytes in the array. invert(self) -> Self692 fn invert(self) -> Self; 693 } 694 695 trait ByteOrderType: FromBytes + AsBytes + Unaligned + Copy + Eq + Debug { 696 type Native: Native; 697 type ByteArray: ByteArray; 698 699 const ZERO: Self; 700 new(native: Self::Native) -> Self701 fn new(native: Self::Native) -> Self; get(self) -> Self::Native702 fn get(self) -> Self::Native; set(&mut self, native: Self::Native)703 fn set(&mut self, native: Self::Native); from_bytes(bytes: Self::ByteArray) -> Self704 fn from_bytes(bytes: Self::ByteArray) -> Self; into_bytes(self) -> Self::ByteArray705 fn into_bytes(self) -> Self::ByteArray; 706 707 /// For `f32` and `f64`, NaN values are not considered equal to 708 /// themselves. This method is like `assert_eq!`, but it treats NaN 709 /// values as equal. assert_eq_or_nan(self, other: Self)710 fn assert_eq_or_nan(self, other: Self) { 711 let slf = (!self.get().is_nan()).then(|| self); 712 let other = (!other.get().is_nan()).then(|| other); 713 assert_eq!(slf, other); 714 } 715 } 716 717 trait ByteOrderTypeUnsigned: ByteOrderType { 718 const MAX_VALUE: Self; 719 } 720 721 macro_rules! impl_byte_array { 722 ($bytes:expr) => { 723 impl ByteArray for [u8; $bytes] { 724 fn invert(mut self) -> [u8; $bytes] { 725 self.reverse(); 726 self 727 } 728 } 729 }; 730 } 731 732 impl_byte_array!(2); 733 impl_byte_array!(4); 734 impl_byte_array!(8); 735 impl_byte_array!(16); 736 737 macro_rules! impl_byte_order_type_unsigned { 738 ($name:ident, unsigned) => { 739 impl<O: ByteOrder> ByteOrderTypeUnsigned for $name<O> { 740 const MAX_VALUE: $name<O> = $name::MAX_VALUE; 741 } 742 }; 743 ($name:ident, signed) => {}; 744 } 745 746 macro_rules! impl_traits { 747 ($name:ident, $native:ident, $bytes:expr, $sign:ident $(, @$float:ident)?) => { 748 impl Native for $native { 749 // For some types, `0 as $native` is required (for example, when 750 // `$native` is a floating-point type; `0` is an integer), but 751 // for other types, it's a trivial cast. In all cases, Clippy 752 // thinks it's dangerous. 753 #[allow(trivial_numeric_casts, clippy::as_conversions)] 754 const ZERO: $native = 0 as $native; 755 const MAX_VALUE: $native = $native::MAX; 756 757 type Distribution = Standard; 758 const DIST: Standard = Standard; 759 760 impl_traits!(@float_dependent_methods $(@$float)?); 761 } 762 763 impl<O: ByteOrder> ByteOrderType for $name<O> { 764 type Native = $native; 765 type ByteArray = [u8; $bytes]; 766 767 const ZERO: $name<O> = $name::ZERO; 768 769 fn new(native: $native) -> $name<O> { 770 $name::new(native) 771 } 772 773 fn get(self) -> $native { 774 $name::get(self) 775 } 776 777 fn set(&mut self, native: $native) { 778 $name::set(self, native) 779 } 780 781 fn from_bytes(bytes: [u8; $bytes]) -> $name<O> { 782 $name::from(bytes) 783 } 784 785 fn into_bytes(self) -> [u8; $bytes] { 786 <[u8; $bytes]>::from(self) 787 } 788 } 789 790 impl_byte_order_type_unsigned!($name, $sign); 791 }; 792 (@float_dependent_methods) => { 793 fn checked_add(self, rhs: Self) -> Option<Self> { self.checked_add(rhs) } 794 fn checked_div(self, rhs: Self) -> Option<Self> { self.checked_div(rhs) } 795 fn checked_mul(self, rhs: Self) -> Option<Self> { self.checked_mul(rhs) } 796 fn checked_rem(self, rhs: Self) -> Option<Self> { self.checked_rem(rhs) } 797 fn checked_sub(self, rhs: Self) -> Option<Self> { self.checked_sub(rhs) } 798 fn checked_shl(self, rhs: Self) -> Option<Self> { self.checked_shl(rhs.try_into().unwrap_or(u32::MAX)) } 799 fn checked_shr(self, rhs: Self) -> Option<Self> { self.checked_shr(rhs.try_into().unwrap_or(u32::MAX)) } 800 fn is_nan(self) -> bool { false } 801 }; 802 (@float_dependent_methods @float) => { 803 fn checked_add(self, rhs: Self) -> Option<Self> { Some(self + rhs) } 804 fn checked_div(self, rhs: Self) -> Option<Self> { Some(self / rhs) } 805 fn checked_mul(self, rhs: Self) -> Option<Self> { Some(self * rhs) } 806 fn checked_rem(self, rhs: Self) -> Option<Self> { Some(self % rhs) } 807 fn checked_sub(self, rhs: Self) -> Option<Self> { Some(self - rhs) } 808 fn checked_shl(self, _rhs: Self) -> Option<Self> { unimplemented!() } 809 fn checked_shr(self, _rhs: Self) -> Option<Self> { unimplemented!() } 810 fn is_nan(self) -> bool { self.is_nan() } 811 }; 812 } 813 814 impl_traits!(U16, u16, 2, unsigned); 815 impl_traits!(U32, u32, 4, unsigned); 816 impl_traits!(U64, u64, 8, unsigned); 817 impl_traits!(U128, u128, 16, unsigned); 818 impl_traits!(I16, i16, 2, signed); 819 impl_traits!(I32, i32, 4, signed); 820 impl_traits!(I64, i64, 8, signed); 821 impl_traits!(I128, i128, 16, signed); 822 impl_traits!(F32, f32, 4, signed, @float); 823 impl_traits!(F64, f64, 8, signed, @float); 824 825 macro_rules! call_for_unsigned_types { 826 ($fn:ident, $byteorder:ident) => { 827 $fn::<U16<$byteorder>>(); 828 $fn::<U32<$byteorder>>(); 829 $fn::<U64<$byteorder>>(); 830 $fn::<U128<$byteorder>>(); 831 }; 832 } 833 834 macro_rules! call_for_signed_types { 835 ($fn:ident, $byteorder:ident) => { 836 $fn::<I16<$byteorder>>(); 837 $fn::<I32<$byteorder>>(); 838 $fn::<I64<$byteorder>>(); 839 $fn::<I128<$byteorder>>(); 840 }; 841 } 842 843 macro_rules! call_for_float_types { 844 ($fn:ident, $byteorder:ident) => { 845 $fn::<F32<$byteorder>>(); 846 $fn::<F64<$byteorder>>(); 847 }; 848 } 849 850 macro_rules! call_for_all_types { 851 ($fn:ident, $byteorder:ident) => { 852 call_for_unsigned_types!($fn, $byteorder); 853 call_for_signed_types!($fn, $byteorder); 854 call_for_float_types!($fn, $byteorder); 855 }; 856 } 857 858 #[cfg(target_endian = "big")] 859 type NonNativeEndian = LittleEndian; 860 #[cfg(target_endian = "little")] 861 type NonNativeEndian = BigEndian; 862 863 // We use a `u64` seed so that we can use `SeedableRng::seed_from_u64`. 864 // `SmallRng`'s `SeedableRng::Seed` differs by platform, so if we wanted to 865 // call `SeedableRng::from_seed`, which takes a `Seed`, we would need 866 // conditional compilation by `target_pointer_width`. 867 const RNG_SEED: u64 = 0x7A03CAE2F32B5B8F; 868 869 const RAND_ITERS: usize = if cfg!(any(miri, kani)) { 870 // The tests below which use this constant used to take a very long time 871 // on Miri, which slows down local development and CI jobs. We're not 872 // using Miri to check for the correctness of our code, but rather its 873 // soundness, and at least in the context of these particular tests, a 874 // single loop iteration is just as good for surfacing UB as multiple 875 // iterations are. 876 // 877 // As of the writing of this comment, here's one set of measurements: 878 // 879 // $ # RAND_ITERS == 1 880 // $ cargo miri test -- -Z unstable-options --report-time endian 881 // test byteorder::tests::test_native_endian ... ok <0.049s> 882 // test byteorder::tests::test_non_native_endian ... ok <0.061s> 883 // 884 // $ # RAND_ITERS == 1024 885 // $ cargo miri test -- -Z unstable-options --report-time endian 886 // test byteorder::tests::test_native_endian ... ok <25.716s> 887 // test byteorder::tests::test_non_native_endian ... ok <38.127s> 888 1 889 } else { 890 1024 891 }; 892 893 #[cfg_attr(test, test)] 894 #[cfg_attr(kani, kani::proof)] test_zero()895 fn test_zero() { 896 fn test_zero<T: ByteOrderType>() { 897 assert_eq!(T::ZERO.get(), T::Native::ZERO); 898 } 899 900 call_for_all_types!(test_zero, NativeEndian); 901 call_for_all_types!(test_zero, NonNativeEndian); 902 } 903 904 #[cfg_attr(test, test)] 905 #[cfg_attr(kani, kani::proof)] test_max_value()906 fn test_max_value() { 907 fn test_max_value<T: ByteOrderTypeUnsigned>() { 908 assert_eq!(T::MAX_VALUE.get(), T::Native::MAX_VALUE); 909 } 910 911 call_for_unsigned_types!(test_max_value, NativeEndian); 912 call_for_unsigned_types!(test_max_value, NonNativeEndian); 913 } 914 915 #[cfg_attr(test, test)] 916 #[cfg_attr(kani, kani::proof)] test_endian()917 fn test_endian() { 918 fn test<T: ByteOrderType>(invert: bool) { 919 let mut r = SmallRng::seed_from_u64(RNG_SEED); 920 for _ in 0..RAND_ITERS { 921 let native = T::Native::rand(&mut r); 922 let mut bytes = T::ByteArray::default(); 923 bytes.as_bytes_mut().copy_from_slice(native.as_bytes()); 924 if invert { 925 bytes = bytes.invert(); 926 } 927 let mut from_native = T::new(native); 928 let from_bytes = T::from_bytes(bytes); 929 930 from_native.assert_eq_or_nan(from_bytes); 931 from_native.get().assert_eq_or_nan(native); 932 from_bytes.get().assert_eq_or_nan(native); 933 934 assert_eq!(from_native.into_bytes(), bytes); 935 assert_eq!(from_bytes.into_bytes(), bytes); 936 937 let updated = T::Native::rand(&mut r); 938 from_native.set(updated); 939 from_native.get().assert_eq_or_nan(updated); 940 } 941 } 942 943 fn test_native<T: ByteOrderType>() { 944 test::<T>(false); 945 } 946 947 fn test_non_native<T: ByteOrderType>() { 948 test::<T>(true); 949 } 950 951 call_for_all_types!(test_native, NativeEndian); 952 call_for_all_types!(test_non_native, NonNativeEndian); 953 } 954 955 #[test] test_ops_impls()956 fn test_ops_impls() { 957 // Test implementations of traits in `core::ops`. Some of these are 958 // fairly banal, but some are optimized to perform the operation without 959 // swapping byte order (namely, bit-wise operations which are identical 960 // regardless of byte order). These are important to test, and while 961 // we're testing those anyway, it's trivial to test all of the impls. 962 963 fn test<T, F, G, H>(op: F, op_native: G, op_native_checked: Option<H>) 964 where 965 T: ByteOrderType, 966 F: Fn(T, T) -> T, 967 G: Fn(T::Native, T::Native) -> T::Native, 968 H: Fn(T::Native, T::Native) -> Option<T::Native>, 969 { 970 let mut r = SmallRng::seed_from_u64(RNG_SEED); 971 for _ in 0..RAND_ITERS { 972 let n0 = T::Native::rand(&mut r); 973 let n1 = T::Native::rand(&mut r); 974 let t0 = T::new(n0); 975 let t1 = T::new(n1); 976 977 // If this operation would overflow/underflow, skip it rather 978 // than attempt to catch and recover from panics. 979 if matches!(&op_native_checked, Some(checked) if checked(n0, n1).is_none()) { 980 continue; 981 } 982 983 let n_res = op_native(n0, n1); 984 let t_res = op(t0, t1); 985 986 // For `f32` and `f64`, NaN values are not considered equal to 987 // themselves. We store `Option<f32>`/`Option<f64>` and store 988 // NaN as `None` so they can still be compared. 989 let n_res = (!T::Native::is_nan(n_res)).then(|| n_res); 990 let t_res = (!T::Native::is_nan(t_res.get())).then(|| t_res.get()); 991 assert_eq!(n_res, t_res); 992 } 993 } 994 995 macro_rules! test { 996 (@binary $trait:ident, $method:ident $([$checked_method:ident])?, $($call_for_macros:ident),*) => {{ 997 test!( 998 @inner $trait, 999 core::ops::$trait::$method, 1000 core::ops::$trait::$method, 1001 { 1002 #[allow(unused_mut, unused_assignments)] 1003 let mut op_native_checked = None::<fn(T::Native, T::Native) -> Option<T::Native>>; 1004 $( 1005 op_native_checked = Some(T::Native::$checked_method); 1006 )? 1007 op_native_checked 1008 }, 1009 $($call_for_macros),* 1010 ); 1011 }}; 1012 (@unary $trait:ident, $method:ident $([$checked_method:ident])?, $($call_for_macros:ident),*) => {{ 1013 test!( 1014 @inner $trait, 1015 |slf, _rhs| core::ops::$trait::$method(slf), 1016 |slf, _rhs| core::ops::$trait::$method(slf), 1017 { 1018 #[allow(unused_mut, unused_assignments)] 1019 let mut op_native_checked = None::<fn(T::Native, T::Native) -> Option<T::Native>>; 1020 $( 1021 op_native_checked = Some(|slf, _rhs| T::Native::$checked_method(slf)); 1022 )? 1023 op_native_checked 1024 }, 1025 $($call_for_macros),* 1026 ); 1027 }}; 1028 (@inner $trait:ident, $op:expr, $op_native:expr, $op_native_checked:expr, $($call_for_macros:ident),*) => {{ 1029 fn t<T: ByteOrderType + core::ops::$trait<Output = T>>() 1030 where 1031 T::Native: core::ops::$trait<Output = T::Native>, 1032 { 1033 test::<T, _, _, _>( 1034 $op, 1035 $op_native, 1036 $op_native_checked, 1037 ); 1038 } 1039 1040 $( 1041 $call_for_macros!(t, NativeEndian); 1042 $call_for_macros!(t, NonNativeEndian); 1043 )* 1044 }}; 1045 } 1046 1047 test!(@binary Add, add[checked_add], call_for_all_types); 1048 test!(@binary Div, div[checked_div], call_for_all_types); 1049 test!(@binary Mul, mul[checked_mul], call_for_all_types); 1050 test!(@binary Rem, rem[checked_rem], call_for_all_types); 1051 test!(@binary Sub, sub[checked_sub], call_for_all_types); 1052 1053 test!(@binary BitAnd, bitand, call_for_unsigned_types, call_for_signed_types); 1054 test!(@binary BitOr, bitor, call_for_unsigned_types, call_for_signed_types); 1055 test!(@binary BitXor, bitxor, call_for_unsigned_types, call_for_signed_types); 1056 test!(@binary Shl, shl[checked_shl], call_for_unsigned_types, call_for_signed_types); 1057 test!(@binary Shr, shr[checked_shr], call_for_unsigned_types, call_for_signed_types); 1058 1059 test!(@unary Not, not, call_for_signed_types, call_for_unsigned_types); 1060 test!(@unary Neg, neg, call_for_signed_types, call_for_float_types); 1061 } 1062 1063 #[test] test_debug_impl()1064 fn test_debug_impl() { 1065 // Ensure that Debug applies format options to the inner value. 1066 let val = U16::<LE>::new(10); 1067 assert_eq!(format!("{:?}", val), "U16(10)"); 1068 assert_eq!(format!("{:03?}", val), "U16(010)"); 1069 assert_eq!(format!("{:x?}", val), "U16(a)"); 1070 } 1071 } 1072