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