#![allow(clippy::len_without_is_empty)]
use core::cell::Cell;
use core::marker::PhantomData;
use core::mem::align_of;
use core::str;
use crate::buf::Buf;
use crate::buf_mut::BufMut;
use crate::error::{Error, ErrorKind};
use crate::visit::Visit;
pub unsafe trait UnsizedZeroCopy {
const ALIGN: usize;
fn size(&self) -> usize;
fn store_to<B: ?Sized>(&self, buf: &mut B) -> Result<(), Error>
where
B: BufMut;
unsafe fn coerce(buf: &Buf) -> Result<&Self, Error>;
unsafe fn coerce_mut(buf: &mut Buf) -> Result<&mut Self, Error>;
}
pub unsafe trait ZeroSized {}
unsafe impl<T> ZeroSized for Cell<T> where T: ZeroSized {}
unsafe impl<T> ZeroCopy for Cell<T>
where
T: Copy + ZeroCopy,
{
const ANY_BITS: bool = T::ANY_BITS;
fn store_to<B: ?Sized>(&self, buf: &mut B) -> Result<(), Error>
where
B: BufMut,
{
let value = self.get();
T::store_to(&value, buf)
}
unsafe fn coerce(buf: &Buf) -> Result<&Self, Error> {
T::validate(buf)?;
Ok(buf.cast())
}
unsafe fn coerce_mut(buf: &mut Buf) -> Result<&mut Self, Error> {
T::validate(buf)?;
Ok(buf.cast_mut())
}
unsafe fn validate(buf: &Buf) -> Result<(), Error> {
T::validate(buf)
}
}
unsafe impl ZeroSized for () {}
unsafe impl<T> ZeroSized for [T; 0] {}
unsafe impl<T: ?Sized> ZeroSized for PhantomData<T> {}
pub unsafe trait ZeroCopy {
const ANY_BITS: bool;
fn store_to<B: ?Sized>(&self, buf: &mut B) -> Result<(), Error>
where
B: BufMut;
unsafe fn coerce(buf: &Buf) -> Result<&Self, Error>;
unsafe fn coerce_mut(buf: &mut Buf) -> Result<&mut Self, Error>;
unsafe fn validate(buf: &Buf) -> Result<(), Error>;
}
unsafe impl UnsizedZeroCopy for str {
const ALIGN: usize = align_of::<u8>();
#[inline]
fn size(&self) -> usize {
<str>::len(self)
}
#[inline]
fn store_to<B: ?Sized>(&self, buf: &mut B) -> Result<(), Error>
where
B: BufMut,
{
buf.extend_from_slice(self.as_bytes())
}
#[inline]
unsafe fn coerce(buf: &Buf) -> Result<&Self, Error> {
str::from_utf8(buf.as_slice()).map_err(|error| Error::new(ErrorKind::Utf8Error { error }))
}
#[inline]
unsafe fn coerce_mut(buf: &mut Buf) -> Result<&mut Self, Error> {
str::from_utf8_mut(buf.as_mut_slice())
.map_err(|error| Error::new(ErrorKind::Utf8Error { error }))
}
}
unsafe impl UnsizedZeroCopy for [u8] {
const ALIGN: usize = align_of::<u8>();
#[inline]
fn size(&self) -> usize {
<[_]>::len(self)
}
#[inline]
fn store_to<B: ?Sized>(&self, buf: &mut B) -> Result<(), Error>
where
B: BufMut,
{
buf.extend_from_slice(self)
}
#[inline]
unsafe fn coerce(buf: &Buf) -> Result<&Self, Error> {
Ok(buf.as_slice())
}
#[inline]
unsafe fn coerce_mut(buf: &mut Buf) -> Result<&mut Self, Error> {
Ok(buf.as_mut_slice())
}
}
macro_rules! impl_number {
($ty:ty) => {
#[doc = concat!(" [`ZeroCopy`] implementation for `", stringify!($ty), "`")]
#[doc = concat!(" field: ", stringify!($ty), ",")]
#[doc = concat!("let size = size_of::<", stringify!($ty) ,">();")]
#[doc = concat!("let zero: ", stringify!($ty), " = 0;")]
#[doc = concat!("let one: ", stringify!($ty), " = 1;")]
unsafe impl ZeroCopy for $ty {
const ANY_BITS: bool = true;
fn store_to<B: ?Sized>(&self, buf: &mut B) -> Result<(), Error>
where
B: BufMut,
{
buf.extend_from_slice(&<$ty>::to_ne_bytes(*self)[..])
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn coerce(buf: &Buf) -> Result<&Self, Error> {
Ok(buf.cast())
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn coerce_mut(buf: &mut Buf) -> Result<&mut Self, Error> {
Ok(buf.cast_mut())
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn validate(_: &Buf) -> Result<(), Error> {
Ok(())
}
}
impl Visit for $ty {
type Target = $ty;
fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
where
V: FnOnce(&Self::Target) -> O,
{
Ok(visitor(self))
}
}
};
}
impl_number!(usize);
impl_number!(isize);
impl_number!(u8);
impl_number!(u16);
impl_number!(u32);
impl_number!(u64);
impl_number!(u128);
impl_number!(i8);
impl_number!(i16);
impl_number!(i32);
impl_number!(i64);
impl_number!(i128);
macro_rules! impl_nonzero_number {
($ty:ident, $example:ty) => {
#[doc = concat!(" [`ZeroCopy`] implementation for `", stringify!($ty), "`")]
#[doc = concat!("use std::num::", stringify!($ty), ";")]
#[doc = concat!(" field: ", stringify!($ty), ",")]
#[doc = concat!("let size = size_of::<", stringify!($example) ,">();")]
#[doc = concat!("let zero: ", stringify!($example), " = 0;")]
#[doc = concat!("let one: ", stringify!($example), " = 1;")]
unsafe impl ZeroCopy for ::core::num::$ty {
const ANY_BITS: bool = false;
fn store_to<B: ?Sized>(&self, buf: &mut B) -> Result<(), Error>
where
B: BufMut,
{
buf.extend_from_slice(&self.get().to_ne_bytes()[..])
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn coerce(buf: &Buf) -> Result<&Self, Error> {
Self::validate(buf)?;
Ok(buf.cast())
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn coerce_mut(buf: &mut Buf) -> Result<&mut Self, Error> {
Self::validate(buf)?;
Ok(buf.cast_mut())
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn validate(buf: &Buf) -> Result<(), Error> {
if buf.is_zeroed() {
return Err(Error::new(ErrorKind::NonZeroZeroed { range: buf.range() }));
}
Ok(())
}
}
impl Visit for ::core::num::$ty {
type Target = ::core::num::$ty;
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 {
($({$name:ident},)? $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 $(<$name>)* ZeroCopy for $ty {
const ANY_BITS: bool = true;
#[inline]
fn store_to<B: ?Sized>(&self, _: &mut B) -> Result<(), Error>
where
B: BufMut,
{
Ok(())
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn coerce(buf: &Buf) -> Result<&Self, Error> {
Ok(buf.cast())
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn coerce_mut(buf: &mut Buf) -> Result<&mut Self, Error> {
Ok(buf.cast_mut())
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn validate(_: &Buf) -> Result<(), Error> {
Ok(())
}
}
impl $(<$name>)* Visit for $ty {
type Target = $ty;
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;
fn store_to<B: ?Sized>(&self, buf: &mut B) -> Result<(), Error>
where
B: BufMut,
{
for element in self {
element.store_to(buf)?;
}
Ok(())
}
unsafe fn coerce_mut(buf: &mut Buf) -> Result<&mut Self, Error> {
crate::buf::validate_array::<T>(buf)?;
Ok(buf.cast_mut())
}
unsafe fn coerce(buf: &Buf) -> Result<&Self, Error> {
crate::buf::validate_array::<T>(buf)?;
Ok(buf.cast())
}
#[allow(clippy::missing_safety_doc)]
unsafe fn validate(buf: &Buf) -> Result<(), Error> {
crate::buf::validate_array::<T>(buf)?;
Ok(())
}
}