#![allow(clippy::missing_safety_doc)]
use core::cell::Cell;
use core::marker::PhantomData;
use core::mem::align_of;
use core::str;
use crate::buf::{Buf, BufMut, Cursor, StructPadder, Visit};
use crate::error::{Error, ErrorKind};
mod sealed {
pub trait Sealed {}
impl Sealed for str {}
impl Sealed for [u8] {}
}
pub unsafe trait UnsizedZeroCopy: self::sealed::Sealed {
const ALIGN: usize;
fn size(&self) -> usize;
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
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;
const PADDED: bool = T::PADDED;
#[inline]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
self.get().store_to(buf);
}
#[inline]
unsafe fn pad(&self, padder: &mut StructPadder<'_, Self>) {
padder.pad(&self.get());
}
#[inline]
unsafe fn validate(cursor: Cursor<'_>) -> Result<(), Error> {
T::validate(cursor)
}
}
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;
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut;
unsafe fn pad(&self, padder: &mut StructPadder<'_, Self>);
unsafe fn validate(cursor: Cursor<'_>) -> Result<(), Error>;
}
unsafe impl UnsizedZeroCopy for str {
const ALIGN: usize = align_of::<u8>();
#[inline]
fn size(&self) -> usize {
<str>::len(self)
}
#[inline]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
buf.store_bytes(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]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
buf.store_bytes(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;
const PADDED: bool = false;
#[inline]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(*self);
}
#[inline]
unsafe fn pad(&self, _: &mut StructPadder<'_, Self>) {}
#[inline]
unsafe fn validate(_: Cursor<'_>) -> Result<(), Error> {
Ok(())
}
}
impl crate::buf::visit::sealed::Sealed for $ty {}
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);
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_float {
($ty:ty) => {
unsafe impl ZeroCopy for $ty {
const ANY_BITS: bool = true;
const PADDED: bool = false;
#[inline]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(*self);
}
#[inline]
unsafe fn pad(&self, _: &mut StructPadder<'_, Self>) {}
#[inline]
unsafe fn validate(_: Cursor<'_>) -> Result<(), Error> {
Ok(())
}
}
impl crate::buf::visit::sealed::Sealed for $ty {}
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);
impl_float!(f64);
unsafe impl ZeroCopy for char {
const ANY_BITS: bool = false;
const PADDED: bool = false;
#[inline]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(*self as u32);
}
#[inline]
unsafe fn pad(&self, _: &mut StructPadder<'_, Self>) {}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn validate(cursor: Cursor<'_>) -> Result<(), Error> {
let repr = unsafe { *cursor.cast::<u32>() };
if char::try_from(repr).is_err() {
return Err(Error::new(ErrorKind::IllegalChar { repr }));
}
Ok(())
}
}
impl crate::buf::visit::sealed::Sealed for char {}
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;
#[inline]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(*self as u8);
}
#[inline]
unsafe fn pad(&self, _: &mut StructPadder<'_, Self>) {}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn validate(cursor: Cursor<'_>) -> Result<(), Error> {
match *cursor.cast::<u8>() {
0 | 1 => (),
repr => return Err(Error::new(ErrorKind::IllegalBool { repr })),
}
Ok(())
}
}
impl crate::buf::visit::sealed::Sealed for bool {}
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 size = size_of::<", stringify!($inner) ,">();")]
#[doc = concat!("let zero: ", stringify!($inner), " = 0;")]
#[doc = concat!("let one: ", stringify!($inner), " = 1;")]
unsafe impl ZeroCopy for ::core::num::$ty {
const ANY_BITS: bool = false;
const PADDED: bool = false;
#[inline]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(self.get());
}
#[inline]
unsafe fn pad(&self, _: &mut StructPadder<'_, Self>) {}
#[inline]
unsafe fn validate(cursor: Cursor<'_>) -> Result<(), Error> {
if *cursor.cast::<$inner>() == 0 {
return Err(Error::new(ErrorKind::NonZeroZeroed {
range: cursor.range::<::core::num::$ty>(),
}));
}
Ok(())
}
}
impl crate::buf::visit::sealed::Sealed for ::core::num::$ty {}
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 {
($({$($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;
#[inline]
unsafe fn store_to<B: ?Sized>(&self, _: &mut B)
where
B: BufMut,
{
}
#[inline]
unsafe fn pad(&self, _: &mut StructPadder<'_, Self>) {
}
#[inline]
unsafe fn validate(_: Cursor<'_>) -> Result<(), Error> {
Ok(())
}
}
impl $(<$($bounds)*>)* crate::buf::visit::sealed::Sealed for $ty {
}
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;
#[inline]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
unsafe {
let mut padder = buf.store_struct(self);
self.pad(&mut padder);
}
}
#[inline]
unsafe fn pad(&self, padder: &mut StructPadder<'_, Self>) {
if T::PADDED {
for value in self {
padder.pad::<T>(value);
}
}
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn validate(cursor: Cursor<'_>) -> Result<(), Error> {
crate::buf::validate_array::<T>(cursor, N)?;
Ok(())
}
}
impl<T> crate::buf::visit::sealed::Sealed for [T; 0] {}
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))
}
}