#![allow(clippy::missing_safety_doc)]
use core::array;
use core::marker::PhantomData;
use core::mem::{align_of, size_of, transmute};
use core::num::Wrapping;
use core::ptr::NonNull;
use core::slice;
use core::str;
use crate::buf::{Buf, Padder, Validator, Visit};
use crate::endian::ByteOrder;
use crate::error::{Error, ErrorKind};
use crate::pointer::{Pointee, Size};
mod sealed {
use crate::ZeroCopy;
pub trait Sealed {}
impl Sealed for str {}
impl<T> Sealed for [T] where T: ZeroCopy {}
}
pub unsafe trait UnsizedZeroCopy: self::sealed::Sealed + Pointee {
const ALIGN: usize;
const PADDED: bool;
fn as_ptr(&self) -> *const u8;
fn metadata(&self) -> Self::Metadata;
unsafe fn pad(&self, pad: &mut Padder<'_, Self>);
unsafe fn validate_unsized<E, O>(
data: NonNull<u8>,
len: usize,
metadata: Self::Stored<O>,
) -> Result<Self::Metadata, Error>
where
E: ByteOrder,
O: Size;
unsafe fn with_metadata(data: NonNull<u8>, metadata: Self::Metadata) -> *const Self;
unsafe fn with_metadata_mut(data: NonNull<u8>, metadata: Self::Metadata) -> *mut Self;
}
pub unsafe trait ZeroSized {}
unsafe impl<T> ZeroSized for Wrapping<T> where T: ZeroSized {}
unsafe impl<T> ZeroCopy for Wrapping<T>
where
T: ZeroCopy,
{
const ANY_BITS: bool = T::ANY_BITS;
const PADDED: bool = T::PADDED;
const CAN_SWAP_BYTES: bool = T::CAN_SWAP_BYTES;
#[inline]
unsafe fn pad(padder: &mut Padder<'_, Self>) {
padder.pad::<T>();
}
#[inline]
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
validator.validate::<T>()
}
#[inline]
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder,
{
Wrapping(T::swap_bytes::<E>(self.0))
}
}
unsafe impl ZeroSized for () {}
unsafe impl<T> ZeroSized for [T; 0] {}
unsafe impl<T: ?Sized> ZeroSized for PhantomData<T> {}
pub unsafe trait ZeroCopy: Sized {
const ANY_BITS: bool;
const PADDED: bool;
const CAN_SWAP_BYTES: bool;
#[doc(hidden)]
unsafe fn pad(padder: &mut Padder<'_, Self>);
#[doc(hidden)]
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error>;
#[inline]
fn initialize_padding(&mut self) {
unsafe {
if Self::PADDED {
let ptr = NonNull::new_unchecked((self as *mut Self).cast::<u8>());
let mut padder = Padder::new(ptr);
Self::pad(&mut padder);
padder.remaining();
}
}
}
#[inline]
fn to_bytes(&mut self) -> &[u8] {
self.initialize_padding();
unsafe {
let ptr = (self as *mut Self).cast::<u8>();
slice::from_raw_parts(ptr, size_of::<Self>())
}
}
#[inline]
unsafe fn to_bytes_unchecked(&self) -> &[u8] {
unsafe {
let ptr = (self as *const Self).cast::<u8>();
slice::from_raw_parts(ptr, size_of::<Self>())
}
}
#[inline]
fn from_bytes(bytes: &[u8]) -> Result<&Self, Error> {
Buf::new(bytes).load_at::<Self>(0)
}
#[inline]
unsafe fn from_bytes_mut(bytes: &mut [u8]) -> Result<&mut Self, Error> {
Buf::new_mut(bytes).load_at_mut::<Self>(0)
}
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder;
}
unsafe impl UnsizedZeroCopy for str {
const ALIGN: usize = align_of::<u8>();
const PADDED: bool = false;
#[inline]
fn as_ptr(&self) -> *const u8 {
str::as_ptr(self)
}
#[inline]
fn metadata(&self) -> Self::Metadata {
str::len(self)
}
#[inline]
unsafe fn pad(&self, _: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate_unsized<E, O>(
data: NonNull<u8>,
len: usize,
metadata: Self::Stored<O>,
) -> Result<Self::Metadata, Error>
where
E: ByteOrder,
O: Size,
{
let metadata = metadata.as_usize::<E>();
if metadata > len {
return Err(Error::new(ErrorKind::OutOfRangeBounds {
range: 0..metadata,
len,
}));
};
let buf = slice::from_raw_parts(data.as_ptr(), metadata);
str::from_utf8(buf).map_err(|error| Error::new(ErrorKind::Utf8Error { error }))?;
Ok(metadata)
}
#[inline]
unsafe fn with_metadata(data: NonNull<u8>, metadata: Self::Metadata) -> *const Self {
let slice = slice::from_raw_parts(data.as_ptr(), metadata);
str::from_utf8_unchecked(slice)
}
#[inline]
unsafe fn with_metadata_mut(data: NonNull<u8>, metadata: Self::Metadata) -> *mut Self {
let slice = slice::from_raw_parts_mut(data.as_ptr(), metadata);
str::from_utf8_unchecked_mut(slice)
}
}
unsafe impl<T> UnsizedZeroCopy for [T]
where
T: ZeroCopy,
{
const ALIGN: usize = align_of::<T>();
const PADDED: bool = T::PADDED;
#[inline]
fn as_ptr(&self) -> *const u8 {
<[T]>::as_ptr(self).cast()
}
#[inline]
unsafe fn pad(&self, padder: &mut Padder<'_, Self>) {
for _ in 0..self.len() {
padder.pad::<T>();
}
}
#[inline]
fn metadata(&self) -> Self::Metadata {
self.len()
}
#[inline]
unsafe fn validate_unsized<E, O>(
data: NonNull<u8>,
len: usize,
metadata: Self::Stored<O>,
) -> Result<Self::Metadata, Error>
where
E: ByteOrder,
O: Size,
{
let metadata = metadata.as_usize::<E>();
let Some(size) = metadata.checked_mul(size_of::<T>()) else {
return Err(Error::new(ErrorKind::LengthOverflow {
len: metadata,
size: size_of::<T>(),
}));
};
if size > len {
return Err(Error::new(ErrorKind::OutOfRangeBounds {
range: 0..metadata,
len,
}));
};
if !T::ANY_BITS {
let mut validator = Validator::<[T]>::new(data);
for _ in 0..metadata {
validator.validate_only::<T>()?;
}
}
Ok(metadata)
}
#[inline]
unsafe fn with_metadata(data: NonNull<u8>, metadata: Self::Metadata) -> *const Self {
slice::from_raw_parts(data.cast().as_ptr(), metadata)
}
#[inline]
unsafe fn with_metadata_mut(data: NonNull<u8>, metadata: Self::Metadata) -> *mut Self {
slice::from_raw_parts_mut(data.cast().as_ptr(), metadata)
}
}
macro_rules! impl_number {
($ty:ty, $from_be:path) => {
#[doc = concat!(" [`ZeroCopy`] implementation for `", stringify!($ty), "`")]
#[doc = concat!(" field: ", stringify!($ty), ",")]
#[doc = concat!("let zero: ", stringify!($ty), " = 0;")]
#[doc = concat!("let one: ", stringify!($ty), " = 1;")]
#[doc = concat!("let zero = ", stringify!($ty), "::to_ne_bytes(0);")]
#[doc = concat!("let zero = buf::aligned_buf::<", stringify!($ty), ">(&zero);")]
#[doc = concat!("let one = ", stringify!($ty), "::to_ne_bytes(1);")]
#[doc = concat!("let one = buf::aligned_buf::<", stringify!($ty), ">(&one);")]
unsafe impl ZeroCopy for $ty {
const ANY_BITS: bool = true;
const PADDED: bool = false;
const CAN_SWAP_BYTES: bool = true;
#[inline]
unsafe fn pad(_: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
Ok(())
}
#[inline]
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder,
{
$from_be(self)
}
}
impl Visit for $ty {
type Target = $ty;
#[inline]
fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
where
V: FnOnce(&Self::Target) -> O,
{
Ok(visitor(self))
}
}
};
}
impl_number!(usize, E::swap_usize);
impl_number!(isize, E::swap_isize);
impl_number!(u8, core::convert::identity);
impl_number!(u16, E::swap_u16);
impl_number!(u32, E::swap_u32);
impl_number!(u64, E::swap_u64);
impl_number!(u128, E::swap_u128);
impl_number!(i8, core::convert::identity);
impl_number!(i16, E::swap_i16);
impl_number!(i32, E::swap_i32);
impl_number!(i64, E::swap_i64);
impl_number!(i128, E::swap_i128);
macro_rules! impl_float {
($ty:ty, $from_fn:path) => {
unsafe impl ZeroCopy for $ty {
const ANY_BITS: bool = true;
const PADDED: bool = false;
const CAN_SWAP_BYTES: bool = true;
#[inline]
unsafe fn pad(_: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
Ok(())
}
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder,
{
$from_fn(self)
}
}
impl Visit for $ty {
type Target = $ty;
#[inline]
fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
where
V: FnOnce(&Self::Target) -> O,
{
Ok(visitor(self))
}
}
};
}
impl_float!(f32, E::swap_f32);
impl_float!(f64, E::swap_f64);
unsafe impl ZeroCopy for char {
const ANY_BITS: bool = false;
const PADDED: bool = false;
const CAN_SWAP_BYTES: bool = false;
#[inline]
unsafe fn pad(_: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
let repr = validator.load_unaligned::<u32>()?;
if char::try_from(repr).is_err() {
return Err(Error::new(ErrorKind::IllegalChar { repr }));
}
Ok(())
}
#[inline]
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder,
{
self
}
}
impl Visit for char {
type Target = char;
#[inline]
fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
where
V: FnOnce(&Self::Target) -> O,
{
Ok(visitor(self))
}
}
unsafe impl ZeroCopy for bool {
const ANY_BITS: bool = false;
const PADDED: bool = false;
const CAN_SWAP_BYTES: bool = true;
#[inline]
unsafe fn pad(_: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
match validator.byte() {
0 | 1 => (),
repr => return Err(Error::new(ErrorKind::IllegalBool { repr })),
}
Ok(())
}
#[inline]
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder,
{
self
}
}
impl Visit for bool {
type Target = bool;
#[inline]
fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
where
V: FnOnce(&Self::Target) -> O,
{
Ok(visitor(self))
}
}
macro_rules! impl_nonzero_number {
($ty:ident, $inner:ty) => {
#[doc = concat!(" [`ZeroCopy`] implementation for `", stringify!($ty), "`")]
#[doc = concat!("use std::num::", stringify!($ty), ";")]
#[doc = concat!(" field: ", stringify!($ty), ",")]
#[doc = concat!("let zero = ", stringify!($inner), "::to_ne_bytes(0);")]
#[doc = concat!("let zero = buf::aligned_buf::<", stringify!($ty), ">(&zero);")]
#[doc = concat!("let one = ", stringify!($inner), "::to_ne_bytes(1);")]
#[doc = concat!("let one = buf::aligned_buf::<", stringify!($ty), ">(&one);")]
unsafe impl ZeroCopy for ::core::num::$ty {
const ANY_BITS: bool = false;
const PADDED: bool = false;
const CAN_SWAP_BYTES: bool = true;
#[inline]
unsafe fn pad(_: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
if validator.load_unaligned::<$inner>()? == 0 {
return Err(Error::new(ErrorKind::NonZeroZeroed {
range: validator.range::<::core::num::$ty>(),
}));
}
Ok(())
}
#[inline]
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder,
{
unsafe {
::core::num::$ty::new_unchecked(<$inner as ZeroCopy>::swap_bytes::<E>(
self.get(),
))
}
}
}
impl Visit for ::core::num::$ty {
type Target = ::core::num::$ty;
#[inline]
fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
where
V: FnOnce(&Self::Target) -> O,
{
Ok(visitor(self))
}
}
#[doc = concat!(" [`ZeroCopy`] implementation for `Option<", stringify!($ty), ">`")]
#[doc = concat!("use std::num::", stringify!($ty), ";")]
#[doc = concat!(" field: Option<", stringify!($ty), ">,")]
#[doc = concat!("let zero = ", stringify!($inner), "::to_ne_bytes(0);")]
#[doc = concat!("let zero = buf::aligned_buf::<", stringify!($ty), ">(&zero);")]
#[doc = concat!("let one = ", stringify!($inner), "::to_ne_bytes(1);")]
#[doc = concat!("let one = buf::aligned_buf::<", stringify!($ty), ">(&one);")]
#[doc = concat!("assert_eq!(st.field, ", stringify!($ty), "::new(1));")]
unsafe impl ZeroCopy for Option<::core::num::$ty> {
const ANY_BITS: bool = true;
const PADDED: bool = false;
const CAN_SWAP_BYTES: bool = true;
#[inline]
unsafe fn pad(_: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
Ok(())
}
#[inline]
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder,
{
unsafe {
transmute(<$inner as ZeroCopy>::swap_bytes::<E>(transmute::<
Self,
$inner,
>(self)))
}
}
}
impl Visit for Option<::core::num::$ty> {
type Target = Option<::core::num::$ty>;
#[inline]
fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
where
V: FnOnce(&Self::Target) -> O,
{
Ok(visitor(self))
}
}
};
}
impl_nonzero_number!(NonZeroUsize, usize);
impl_nonzero_number!(NonZeroIsize, isize);
impl_nonzero_number!(NonZeroU8, u8);
impl_nonzero_number!(NonZeroU16, u16);
impl_nonzero_number!(NonZeroU32, u32);
impl_nonzero_number!(NonZeroU64, u64);
impl_nonzero_number!(NonZeroU128, u128);
impl_nonzero_number!(NonZeroI8, i8);
impl_nonzero_number!(NonZeroI16, i16);
impl_nonzero_number!(NonZeroI32, i32);
impl_nonzero_number!(NonZeroI64, i64);
impl_nonzero_number!(NonZeroI128, i128);
macro_rules! impl_zst {
($({$($bounds:tt)*},)? $ty:ty, $expr:expr , {$example:ty $(, $import:path)?}) => {
#[doc = concat!(" [`ZeroCopy`] implementation for `", stringify!($ty), "`")]
$(#[doc = concat!("use ", stringify!($import), ";")])*
#[doc = concat!(" field: ", stringify!($example), ",")]
unsafe impl $(<$($bounds)*>)* ZeroCopy for $ty {
const ANY_BITS: bool = true;
const PADDED: bool = false;
const CAN_SWAP_BYTES: bool = true;
#[inline]
unsafe fn pad(_: &mut Padder<'_, Self>) {
}
#[inline]
unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
Ok(())
}
#[inline]
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder,
{
self
}
}
impl $(<$($bounds)*>)* Visit for $ty {
type Target = $ty;
#[inline]
fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
where
V: FnOnce(&Self::Target) -> O,
{
Ok(visitor(self))
}
}
};
}
impl_zst!((), (), { () });
impl_zst!({T}, PhantomData<T>, PhantomData, {PhantomData<u32>, std::marker::PhantomData});
unsafe impl<T, const N: usize> ZeroCopy for [T; N]
where
T: ZeroCopy,
{
const ANY_BITS: bool = T::ANY_BITS;
const PADDED: bool = T::PADDED;
const CAN_SWAP_BYTES: bool = T::CAN_SWAP_BYTES;
#[inline]
unsafe fn pad(padder: &mut Padder<'_, Self>) {
for _ in 0..N {
padder.pad::<T>();
}
}
#[inline]
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
for _ in 0..N {
validator.validate_only::<T>()?;
}
Ok(())
}
#[inline]
fn swap_bytes<E>(self) -> Self
where
E: ByteOrder,
{
let mut iter = self.into_iter();
array::from_fn(move |_| T::swap_bytes::<E>(iter.next().unwrap()))
}
}
impl<T> Visit for [T; 0] {
type Target = [T; 0];
#[inline]
fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
where
V: FnOnce(&Self::Target) -> O,
{
Ok(visitor(self))
}
}