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