#![allow(clippy::missing_safety_doc)]
use core::marker::PhantomData;
use core::mem::{align_of, size_of, size_of_val};
use core::num::Wrapping;
use core::slice;
use core::str;
use crate::buf::{Buf, BufMut, Padder, Validator, Visit};
use crate::error::{Error, ErrorKind};
mod sealed {
pub trait Sealed {}
impl Sealed for str {}
}
pub unsafe trait UnsizedZeroCopy: self::sealed::Sealed {
const ALIGN: usize;
const SIZE: usize;
fn size(&self) -> usize;
fn bytes(&self) -> usize;
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut;
unsafe fn coerce(buf: *const u8, size: usize) -> Result<*const Self, Error>;
unsafe fn coerce_mut(buf: *mut u8, size: usize) -> Result<*mut Self, Error>;
}
pub unsafe trait ZeroSized {}
unsafe impl<T> ZeroSized for Wrapping<T> where T: ZeroSized {}
unsafe impl<T> ZeroCopy for Wrapping<T>
where
T: Copy + ZeroCopy,
{
const ANY_BITS: bool = T::ANY_BITS;
const PADDED: bool = T::PADDED;
#[inline]
unsafe fn store_to<B: ?Sized>(this: *const Self, buf: &mut B)
where
B: BufMut,
{
T::store_to(this.cast(), buf);
}
#[inline]
unsafe fn pad(this: *const Self, padder: &mut Padder<'_, Self>) {
padder.pad(this.cast::<T>());
}
#[inline]
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
validator.validate::<T>()
}
}
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>(this: *const Self, buf: &mut B)
where
B: BufMut;
unsafe fn pad(this: *const Self, padder: &mut Padder<'_, Self>);
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error>;
}
unsafe impl UnsizedZeroCopy for str {
const ALIGN: usize = align_of::<u8>();
const SIZE: usize = size_of::<u8>();
#[inline]
fn size(&self) -> usize {
<str>::len(self)
}
#[inline]
fn bytes(&self) -> usize {
size_of_val(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: *const u8, size: usize) -> Result<*const Self, Error> {
let buf = slice::from_raw_parts(buf, size);
Ok(str::from_utf8(buf).map_err(|error| Error::new(ErrorKind::Utf8Error { error }))?)
}
#[inline]
unsafe fn coerce_mut(buf: *mut u8, size: usize) -> Result<*mut Self, Error> {
let buf = slice::from_raw_parts_mut(buf, size);
Ok(str::from_utf8_mut(buf).map_err(|error| Error::new(ErrorKind::Utf8Error { error }))?)
}
}
macro_rules! impl_unsized_primitive {
({$($param:ident)?}, $ty:ty, $example_ty:ty, $example:expr $(, $import:path)?) => {
impl $(<$param>)* self::sealed::Sealed for [$ty] {}
#[doc = concat!("[`UnsizedZeroCopy`] implementation for [", stringify!($ty), "]")]
$(#[doc = concat!("use ", stringify!($import), ";")])*
#[doc = concat!("struct Custom", stringify!($(<$param>)*) ," { field: Unsized<[", stringify!($ty) ,"]> }")]
#[doc = concat!("let unsize: Unsized<[", stringify!($example_ty), "]> = buf.store_unsized(&", stringify!($example), ");")]
#[doc = concat!("assert_eq!(buf.load(unsize)?, &", stringify!($example), ");")]
#[allow(rustdoc::invalid_html_tags)]
unsafe impl $(<$param>)* UnsizedZeroCopy for [$ty] {
const ALIGN: usize = align_of::<$ty>();
const SIZE: usize = size_of::<$ty>();
#[inline]
fn size(&self) -> usize {
self.len()
}
#[inline]
fn bytes(&self) -> usize {
size_of_val(self)
}
#[inline]
unsafe fn store_to<B: ?Sized>(&self, buf: &mut B)
where
B: BufMut,
{
buf.store_bytes(self);
}
#[inline]
unsafe fn coerce(buf: *const u8, size: usize) -> Result<*const Self, Error> {
Ok(slice::from_raw_parts(buf.cast(), size))
}
#[inline]
unsafe fn coerce_mut(buf: *mut u8, size: usize) -> Result<*mut Self, Error> {
Ok(slice::from_raw_parts_mut(buf.cast(), size))
}
}
};
}
impl_unsized_primitive!({}, u8, u8, [u8::MIN, 1, 2, 3, 4, u8::MAX]);
impl_unsized_primitive!({}, i8, i8, [i8::MIN, -1, 2, -3, 4, i8::MAX]);
impl_unsized_primitive!({}, u16, u16, [u16::MIN, 1, 2, 3, 4, u16::MAX]);
impl_unsized_primitive!({}, i16, i16, [i16::MIN, -1, 2, -3, 4, i16::MAX]);
impl_unsized_primitive!({}, u32, u32, [u32::MIN, 1, 2, 3, 4, u32::MAX]);
impl_unsized_primitive!({}, i32, i32, [i32::MIN, -1, 2, -3, 4, i32::MAX]);
impl_unsized_primitive!({}, u64, u64, [u64::MIN, 1, 2, 3, 4, u64::MAX]);
impl_unsized_primitive!({}, i64, i64, [i64::MIN, -1, 2, -3, 4, i64::MAX]);
impl_unsized_primitive!({}, u128, u128, [u128::MIN, 1, 2, 3, 4, u128::MAX]);
impl_unsized_primitive!({}, i128, i128, [i128::MIN, -1, 2, -3, 4, i128::MAX]);
impl_unsized_primitive!({}, (), (), [(), ()]);
impl_unsized_primitive!(
{ T },
PhantomData<T>,
PhantomData<u32>,
[PhantomData, PhantomData],
std::marker::PhantomData
);
macro_rules! impl_number {
($ty:ty) => {
#[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;
#[inline]
unsafe fn store_to<B: ?Sized>(this: *const Self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(this);
}
#[inline]
unsafe fn pad(_: *const Self, _: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
Ok(())
}
}
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>(this: *const Self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(this);
}
#[inline]
unsafe fn pad(_: *const Self, _: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
Ok(())
}
}
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>(this: *const Self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(this.cast::<u32>());
}
#[inline]
unsafe fn pad(_: *const Self, _: &mut Padder<'_, Self>) {}
#[allow(clippy::missing_safety_doc)]
#[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(())
}
}
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>(this: *const Self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(this.cast::<u8>());
}
#[inline]
unsafe fn pad(_: *const Self, _: &mut Padder<'_, Self>) {}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
match validator.byte() {
0 | 1 => (),
repr => return Err(Error::new(ErrorKind::IllegalBool { repr })),
}
Ok(())
}
}
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;
#[inline]
unsafe fn store_to<B: ?Sized>(this: *const Self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(this.cast::<$inner>());
}
#[inline]
unsafe fn pad(_: *const Self, _: &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(())
}
}
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;
#[inline]
unsafe fn store_to<B: ?Sized>(this: *const Self, buf: &mut B)
where
B: BufMut,
{
buf.store_bits(this.cast::<$inner>());
}
#[inline]
unsafe fn pad(_: *const Self, _: &mut Padder<'_, Self>) {}
#[inline]
unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
Ok(())
}
}
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;
#[inline]
unsafe fn store_to<B: ?Sized>(_: *const Self, _: &mut B)
where
B: BufMut,
{
}
#[inline]
unsafe fn pad(_: *const Self, _: &mut Padder<'_, Self>) {
}
#[inline]
unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
Ok(())
}
}
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>(this: *const Self, buf: &mut B)
where
B: BufMut,
{
unsafe {
let mut padder = buf.store_struct(this);
Self::pad(this, &mut padder);
}
}
#[inline]
unsafe fn pad(this: *const Self, padder: &mut Padder<'_, Self>) {
if T::PADDED {
let mut first = this.cast::<T>();
for _ in 0..N {
padder.pad::<T>(first);
first = first.add(1);
}
}
}
#[allow(clippy::missing_safety_doc)]
#[inline]
unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
crate::buf::validate_array::<_, T>(validator, N)?;
Ok(())
}
}
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))
}
}