1596 lines · 54.5 KB · Rust
RawDownload
// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT//// Copyright 2019 The Fuchsia Authors//// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.// This file may not be copied, modified, or distributed except according to// those terms. //! Byte order-aware numeric primitives.//!//! This module contains equivalents of the native multi-byte integer types with//! no alignment requirement and supporting byte order conversions.//!//! For each native multi-byte integer type - `u16`, `i16`, `u32`, etc - and//! floating point type - `f32` and `f64` - an equivalent type is defined by//! this module - [`U16`], [`I16`], [`U32`], [`F32`], [`F64`], etc. Unlike their//! native counterparts, these types have alignment 1, and take a type parameter//! specifying the byte order in which the bytes are stored in memory. Each type//! implements this crate's relevant conversion and marker traits.//!//! These two properties, taken together, make these types useful for defining//! data structures whose memory layout matches a wire format such as that of a//! network protocol or a file format. Such formats often have multi-byte values//! at offsets that do not respect the alignment requirements of the equivalent//! native types, and stored in a byte order not necessarily the same as that of//! the target platform.//!//! Type aliases are provided for common byte orders in the [`big_endian`],//! [`little_endian`], [`network_endian`], and [`native_endian`] submodules.//! Note that network-endian is a synonym for big-endian.//!//! # Example//!//! One use of these types is for representing network packet formats, such as//! UDP://!//! ```rust//! use zerocopy::{*, byteorder::network_endian::U16};//! # use zerocopy_derive::*;//!//! #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]//! #[repr(C)]//! struct UdpHeader {//!     src_port: U16,//!     dst_port: U16,//!     length: U16,//!     checksum: U16,//! }//!//! #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]//! #[repr(C, packed)]//! struct UdpPacket {//!     header: UdpHeader,//!     body: [u8],//! }//!//! impl UdpPacket {//!     fn parse(bytes: &[u8]) -> Option<&UdpPacket> {//!         UdpPacket::ref_from_bytes(bytes).ok()//!     }//! }//! ``` use core::{    convert::{TryFrom, TryInto},    fmt::{Binary, Debug, LowerHex, Octal, UpperHex},    hash::Hash,    num::TryFromIntError,}; use super::*; /// A type-level representation of byte order.////// This type is implemented by [`BigEndian`] and [`LittleEndian`], which/// represent big-endian and little-endian byte order respectively. This module/// also provides a number of useful aliases for those types: [`NativeEndian`],/// [`NetworkEndian`], [`BE`], and [`LE`].////// `ByteOrder` types can be used to specify the byte order of the types in this/// module - for example, [`U32<BigEndian>`] is a 32-bit integer stored in/// big-endian byte order.////// [`U32<BigEndian>`]: U32pub trait ByteOrder:    Copy + Clone + Debug + Display + Eq + PartialEq + Ord + PartialOrd + Hash + private::Sealed{    #[doc(hidden)]    const ORDER: Order;} mod private {    pub trait Sealed {}     impl Sealed for super::BigEndian {}    impl Sealed for super::LittleEndian {}} #[allow(missing_copy_implementations, missing_debug_implementations)]#[doc(hidden)]#[derive(PartialEq)]pub enum Order {    BigEndian,    LittleEndian,} /// Big-endian byte order.////// See [`ByteOrder`] for more details.#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]pub enum BigEndian {} impl ByteOrder for BigEndian {    const ORDER: Order = Order::BigEndian;} impl Display for BigEndian {    #[inline]    fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {        match *self {}    }} /// Little-endian byte order.////// See [`ByteOrder`] for more details.#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]pub enum LittleEndian {} impl ByteOrder for LittleEndian {    const ORDER: Order = Order::LittleEndian;} impl Display for LittleEndian {    #[inline]    fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {        match *self {}    }} /// The endianness used by this platform.////// This is a type alias for [`BigEndian`] or [`LittleEndian`] depending on the/// endianness of the target platform.#[cfg(target_endian = "big")]pub type NativeEndian = BigEndian; /// The endianness used by this platform.////// This is a type alias for [`BigEndian`] or [`LittleEndian`] depending on the/// endianness of the target platform.#[cfg(target_endian = "little")]pub type NativeEndian = LittleEndian; /// The endianness used in many network protocols.////// This is a type alias for [`BigEndian`].pub type NetworkEndian = BigEndian; /// A type alias for [`BigEndian`].pub type BE = BigEndian; /// A type alias for [`LittleEndian`].pub type LE = LittleEndian; macro_rules! impl_dbg_trait {    ($name:ident, $native:ident) => {        impl<O: ByteOrder> Debug for $name<O> {            #[inline]            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {                // This results in a format like "U16(42)".                f.debug_tuple(stringify!($name)).field(&self.get()).finish()            }        }    };} macro_rules! impl_dbg_traits {    ($name:ident, $native:ident, "floating point number") => {        #[cfg(not(no_fp_fmt_parse))]        impl_dbg_trait!($name, $native);         #[cfg(no_fp_fmt_parse)]        impl<O: ByteOrder> Debug for $name<O> {            #[inline]            fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {                panic!("floating point support is turned off");            }        }    };    ($name:ident, $native:ident, "unsigned integer") => {        impl_dbg_traits!($name, $native, @all_types);    };    ($name:ident, $native:ident, "signed integer") => {        impl_dbg_traits!($name, $native, @all_types);    };    ($name:ident, $native:ident, @all_types) => {        impl_dbg_trait!($name, $native);    };} macro_rules! impl_fmt_trait {    ($name:ident, $native:ident, $trait:ident) => {        impl<O: ByteOrder> $trait for $name<O> {            #[inline(always)]            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {                $trait::fmt(&self.get(), f)            }        }    };} macro_rules! impl_fmt_traits {    ($name:ident, $native:ident, "floating point number") => {        #[cfg(not(no_fp_fmt_parse))]        impl_fmt_trait!($name, $native, Display);    };    ($name:ident, $native:ident, "unsigned integer") => {        impl_fmt_traits!($name, $native, @all_types);    };    ($name:ident, $native:ident, "signed integer") => {        impl_fmt_traits!($name, $native, @all_types);    };    ($name:ident, $native:ident, @all_types) => {        impl_fmt_trait!($name, $native, Display);        impl_fmt_trait!($name, $native, Octal);        impl_fmt_trait!($name, $native, LowerHex);        impl_fmt_trait!($name, $native, UpperHex);        impl_fmt_trait!($name, $native, Binary);    };} macro_rules! impl_ops_traits {    ($name:ident, $native:ident, "floating point number") => {        impl_ops_traits!($name, $native, @all_types);        impl_ops_traits!($name, $native, @signed_integer_floating_point);         impl<O: ByteOrder> PartialOrd for $name<O> {            #[inline(always)]            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {                self.get().partial_cmp(&other.get())            }        }    };    ($name:ident, $native:ident, "unsigned integer") => {        impl_ops_traits!($name, $native, @signed_unsigned_integer);        impl_ops_traits!($name, $native, @all_types);    };    ($name:ident, $native:ident, "signed integer") => {        impl_ops_traits!($name, $native, @signed_unsigned_integer);        impl_ops_traits!($name, $native, @signed_integer_floating_point);        impl_ops_traits!($name, $native, @all_types);    };    ($name:ident, $native:ident, @signed_unsigned_integer) => {        impl_ops_traits!(@without_byteorder_swap $name, $native, BitAnd, bitand, BitAndAssign, bitand_assign);        impl_ops_traits!(@without_byteorder_swap $name, $native, BitOr, bitor, BitOrAssign, bitor_assign);        impl_ops_traits!(@without_byteorder_swap $name, $native, BitXor, bitxor, BitXorAssign, bitxor_assign);        impl_ops_traits!(@with_byteorder_swap $name, $native, Shl, shl, ShlAssign, shl_assign);        impl_ops_traits!(@with_byteorder_swap $name, $native, Shr, shr, ShrAssign, shr_assign);         impl<O> core::ops::Not for $name<O> {            type Output = $name<O>;             #[inline(always)]            fn not(self) -> $name<O> {                 let self_native = $native::from_ne_bytes(self.0);                 $name((!self_native).to_ne_bytes(), PhantomData)            }        }         impl<O: ByteOrder> PartialOrd for $name<O> {            #[inline(always)]            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {                Some(self.cmp(other))            }        }         impl<O: ByteOrder> Ord for $name<O> {            #[inline(always)]            fn cmp(&self, other: &Self) -> Ordering {                self.get().cmp(&other.get())            }        }         impl<O: ByteOrder> PartialOrd<$native> for $name<O> {            #[inline(always)]            fn partial_cmp(&self, other: &$native) -> Option<Ordering> {                self.get().partial_cmp(other)            }        }    };    ($name:ident, $native:ident, @signed_integer_floating_point) => {        impl<O: ByteOrder> core::ops::Neg for $name<O> {            type Output = $name<O>;             #[inline(always)]            fn neg(self) -> $name<O> {                let self_native: $native = self.get();                #[allow(clippy::arithmetic_side_effects)]                $name::<O>::new(-self_native)            }        }    };    ($name:ident, $native:ident, @all_types) => {        impl_ops_traits!(@with_byteorder_swap $name, $native, Add, add, AddAssign, add_assign);        impl_ops_traits!(@with_byteorder_swap $name, $native, Div, div, DivAssign, div_assign);        impl_ops_traits!(@with_byteorder_swap $name, $native, Mul, mul, MulAssign, mul_assign);        impl_ops_traits!(@with_byteorder_swap $name, $native, Rem, rem, RemAssign, rem_assign);        impl_ops_traits!(@with_byteorder_swap $name, $native, Sub, sub, SubAssign, sub_assign);    };    (@with_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => {        impl<O: ByteOrder> core::ops::$trait<$name<O>> for $name<O> {            type Output = $name<O>;             #[inline(always)]            fn $method(self, rhs: $name<O>) -> $name<O> {                let self_native: $native = self.get();                let rhs_native: $native = rhs.get();                let result_native = core::ops::$trait::$method(self_native, rhs_native);                $name::<O>::new(result_native)            }        }         impl<O: ByteOrder> core::ops::$trait<$name<O>> for $native {            type Output = $name<O>;             #[inline(always)]            fn $method(self, rhs: $name<O>) -> $name<O> {                let rhs_native: $native = rhs.get();                let result_native = core::ops::$trait::$method(self, rhs_native);                $name::<O>::new(result_native)            }        }         impl<O: ByteOrder> core::ops::$trait<$native> for $name<O> {            type Output = $name<O>;             #[inline(always)]            fn $method(self, rhs: $native) -> $name<O> {                let self_native: $native = self.get();                let result_native = core::ops::$trait::$method(self_native, rhs);                $name::<O>::new(result_native)            }        }         impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $name<O> {            #[inline(always)]            fn $method_assign(&mut self, rhs: $name<O>) {                *self = core::ops::$trait::$method(*self, rhs);            }        }         impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $native {            #[inline(always)]            fn $method_assign(&mut self, rhs: $name<O>) {                let rhs_native: $native = rhs.get();                *self = core::ops::$trait::$method(*self, rhs_native);            }        }         impl<O: ByteOrder> core::ops::$trait_assign<$native> for $name<O> {            #[inline(always)]            fn $method_assign(&mut self, rhs: $native) {                *self = core::ops::$trait::$method(*self, rhs);            }        }    };    // Implement traits in terms of the same trait on the native type, but    // without performing a byte order swap when both operands are byteorder    // types. This only works for bitwise operations like `&`, `|`, etc.    //    // When only one operand is a byteorder type, we still need to perform a    // byteorder swap.    (@without_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => {        impl<O: ByteOrder> core::ops::$trait<$name<O>> for $name<O> {            type Output = $name<O>;             #[inline(always)]            fn $method(self, rhs: $name<O>) -> $name<O> {                let self_native = $native::from_ne_bytes(self.0);                let rhs_native = $native::from_ne_bytes(rhs.0);                let result_native = core::ops::$trait::$method(self_native, rhs_native);                $name(result_native.to_ne_bytes(), PhantomData)            }        }         impl<O: ByteOrder> core::ops::$trait<$name<O>> for $native {            type Output = $name<O>;             #[inline(always)]            fn $method(self, rhs: $name<O>) -> $name<O> {                // No runtime cost - just byte packing                let rhs_native = $native::from_ne_bytes(rhs.0);                // (Maybe) runtime cost - byte order swap                let slf_byteorder = $name::<O>::new(self);                // No runtime cost - just byte packing                let slf_native = $native::from_ne_bytes(slf_byteorder.0);                // Runtime cost - perform the operation                let result_native = core::ops::$trait::$method(slf_native, rhs_native);                // No runtime cost - just byte unpacking                $name(result_native.to_ne_bytes(), PhantomData)            }        }         impl<O: ByteOrder> core::ops::$trait<$native> for $name<O> {            type Output = $name<O>;             #[inline(always)]            fn $method(self, rhs: $native) -> $name<O> {                // (Maybe) runtime cost - byte order swap                let rhs_byteorder = $name::<O>::new(rhs);                // No runtime cost - just byte packing                let rhs_native = $native::from_ne_bytes(rhs_byteorder.0);                // No runtime cost - just byte packing                let slf_native = $native::from_ne_bytes(self.0);                // Runtime cost - perform the operation                let result_native = core::ops::$trait::$method(slf_native, rhs_native);                // No runtime cost - just byte unpacking                $name(result_native.to_ne_bytes(), PhantomData)            }        }         impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $name<O> {            #[inline(always)]            fn $method_assign(&mut self, rhs: $name<O>) {                *self = core::ops::$trait::$method(*self, rhs);            }        }         impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $native {            #[inline(always)]            fn $method_assign(&mut self, rhs: $name<O>) {                // (Maybe) runtime cost - byte order swap                let rhs_native = rhs.get();                // Runtime cost - perform the operation                *self = core::ops::$trait::$method(*self, rhs_native);            }        }         impl<O: ByteOrder> core::ops::$trait_assign<$native> for $name<O> {            #[inline(always)]            fn $method_assign(&mut self, rhs: $native) {                *self = core::ops::$trait::$method(*self, rhs);            }        }    };} macro_rules! doc_comment {    ($x:expr, $($tt:tt)*) => {        #[doc = $x]        $($tt)*    };} macro_rules! define_max_value_constant {    ($name:ident, $bytes:expr, "unsigned integer") => {        /// The maximum value.        ///        /// This constant should be preferred to constructing a new value using        /// `new`, as `new` may perform an endianness swap depending on the        /// endianness `O` and the endianness of the platform.        pub const MAX_VALUE: $name<O> = $name([0xFFu8; $bytes], PhantomData);    };    // We don't provide maximum and minimum value constants for signed values    // and floats because there's no way to do it generically - it would require    // a different value depending on the value of the `ByteOrder` type    // parameter. Currently, one workaround would be to provide implementations    // for concrete implementations of that trait. In the long term, if we are    // ever able to make the `new` constructor a const fn, we could use that    // instead.    ($name:ident, $bytes:expr, "signed integer") => {};    ($name:ident, $bytes:expr, "floating point number") => {};} macro_rules! define_type {    (        $article:ident,        $description:expr,        $name:ident,        $native:ident,        $bits:expr,        $bytes:expr,        $from_be_fn:path,        $to_be_fn:path,        $from_le_fn:path,        $to_le_fn:path,        $number_kind:tt,        [$($larger_native:ty),*],        [$($larger_native_try:ty),*],        [$($larger_byteorder:ident),*],        [$($larger_byteorder_try:ident),*]    ) => {        doc_comment! {            concat!($description, " stored in a given byte order. `", stringify!($name), "` is like the native `", stringify!($native), "` type withtwo major differences: First, it has no alignment requirement (its alignment is 1).

Lines 1–500 of 1596.