// 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>`]: U32
pub 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)]
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_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") => {
};
($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
|