use {
crate::{
error::{ReadResult, WriteResult},
io::{Reader, Writer},
schema::{SchemaRead, SchemaWrite},
TypeMeta, ZeroCopy,
},
core::{marker::PhantomData, mem::MaybeUninit, ptr},
};
#[cfg(feature = "alloc")]
use {
crate::{
len::{BincodeLen, SeqLen},
schema::{size_of_elem_iter, size_of_elem_slice, write_elem_iter, write_elem_slice},
},
alloc::{boxed::Box as AllocBox, collections, rc::Rc as AllocRc, sync::Arc as AllocArc, vec},
core::mem::{self, ManuallyDrop},
};
#[cfg(feature = "alloc")]
pub struct Vec<T, Len = BincodeLen>(PhantomData<Len>, PhantomData<T>);
#[cfg(feature = "alloc")]
pub struct VecDeque<T, Len = BincodeLen>(PhantomData<Len>, PhantomData<T>);
#[cfg(feature = "alloc")]
pub struct Box<T: ?Sized, Len = BincodeLen>(PhantomData<T>, PhantomData<Len>);
#[cfg(feature = "alloc")]
pub struct Rc<T: ?Sized, Len = BincodeLen>(PhantomData<T>, PhantomData<Len>);
#[cfg(feature = "alloc")]
pub struct Arc<T: ?Sized, Len = BincodeLen>(PhantomData<T>, PhantomData<Len>);
#[cfg(feature = "bytes")]
pub struct Bytes<Len = BincodeLen>(PhantomData<Len>);
#[cfg(feature = "bytes")]
pub struct BytesMut<Len = BincodeLen>(PhantomData<Len>);
#[deprecated(
since = "0.2.0",
note = "Elem is no longer needed for container usage. Use `T` directly instead."
)]
pub struct Elem<T>(PhantomData<T>);
pub struct Pod<T: Copy + 'static>(PhantomData<T>);
unsafe impl<T> ZeroCopy for Pod<T> where T: Copy + 'static {}
impl<T> SchemaWrite for Pod<T>
where
T: Copy + 'static,
{
type Src = T;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<T>(),
zero_copy: true,
};
#[inline]
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(size_of::<T>())
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
unsafe { Ok(writer.write_t(src)?) }
}
}
impl<'de, T> SchemaRead<'de> for Pod<T>
where
T: Copy + 'static,
{
type Dst = T;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<T>(),
zero_copy: true,
};
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
unsafe { Ok(reader.copy_into_t(dst)?) }
}
}
#[allow(deprecated)]
impl<T> SchemaWrite for Elem<T>
where
T: SchemaWrite,
{
type Src = T::Src;
const TYPE_META: TypeMeta = T::TYPE_META;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
T::size_of(src)
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
T::write(writer, src)
}
}
#[allow(deprecated)]
impl<'de, T> SchemaRead<'de> for Elem<T>
where
T: SchemaRead<'de>,
{
type Dst = T::Dst;
const TYPE_META: TypeMeta = T::TYPE_META;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
T::read(reader, dst)
}
}
#[cfg(feature = "alloc")]
impl<T, Len> SchemaWrite for Vec<T, Len>
where
Len: SeqLen,
T: SchemaWrite,
T::Src: Sized,
{
type Src = vec::Vec<T::Src>;
#[inline(always)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
size_of_elem_slice::<T, Len>(src)
}
#[inline(always)]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
write_elem_slice::<T, Len>(writer, src)
}
}
#[cfg(feature = "alloc")]
impl<'de, T, Len> SchemaRead<'de> for Vec<T, Len>
where
Len: SeqLen,
T: SchemaRead<'de>,
{
type Dst = vec::Vec<T::Dst>;
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = Len::read::<T::Dst>(reader)?;
let mut vec: vec::Vec<T::Dst> = vec::Vec::with_capacity(len);
match T::TYPE_META {
TypeMeta::Static {
zero_copy: true, ..
} => {
let spare_capacity = vec.spare_capacity_mut();
unsafe { reader.copy_into_slice_t(spare_capacity)? };
unsafe { vec.set_len(len) };
}
TypeMeta::Static {
size,
zero_copy: false,
} => {
let mut ptr = vec.as_mut_ptr().cast::<MaybeUninit<T::Dst>>();
#[allow(clippy::arithmetic_side_effects)]
let mut reader = unsafe { reader.as_trusted_for(size * len) }?;
for i in 0..len {
T::read(&mut reader, unsafe { &mut *ptr })?;
unsafe {
ptr = ptr.add(1);
#[allow(clippy::arithmetic_side_effects)]
vec.set_len(i + 1);
}
}
}
TypeMeta::Dynamic => {
let mut ptr = vec.as_mut_ptr().cast::<MaybeUninit<T::Dst>>();
for i in 0..len {
T::read(reader, unsafe { &mut *ptr })?;
unsafe {
ptr = ptr.add(1);
#[allow(clippy::arithmetic_side_effects)]
vec.set_len(i + 1);
}
}
}
}
dst.write(vec);
Ok(())
}
}
pub(crate) struct SliceDropGuard<T> {
ptr: *mut MaybeUninit<T>,
initialized_len: usize,
}
impl<T> SliceDropGuard<T> {
pub(crate) fn new(ptr: *mut MaybeUninit<T>) -> Self {
Self {
ptr,
initialized_len: 0,
}
}
#[inline(always)]
#[allow(clippy::arithmetic_side_effects)]
pub(crate) fn inc_len(&mut self) {
self.initialized_len += 1;
}
}
impl<T> Drop for SliceDropGuard<T> {
#[inline(always)]
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
self.ptr.cast::<T>(),
self.initialized_len,
));
}
}
}
macro_rules! impl_heap_slice {
($container:ident => $target:ident) => {
#[cfg(feature = "alloc")]
impl<T, Len> SchemaWrite for $container<[T], Len>
where
Len: SeqLen,
T: SchemaWrite,
T::Src: Sized,
{
type Src = $target<[T::Src]>;
#[inline(always)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
size_of_elem_slice::<T, Len>(src)
}
#[inline(always)]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
write_elem_slice::<T, Len>(writer, src)
}
}
#[cfg(feature = "alloc")]
impl<'de, T, Len> SchemaRead<'de> for $container<[T], Len>
where
Len: SeqLen,
T: SchemaRead<'de>,
{
type Dst = $target<[T::Dst]>;
#[inline(always)]
fn read(
reader: &mut impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
struct DropGuardRawCopy<T>(*mut [MaybeUninit<T>]);
impl<T> Drop for DropGuardRawCopy<T> {
#[inline]
fn drop(&mut self) {
let container = unsafe { $target::from_raw(self.0) };
drop(container);
}
}
struct DropGuardElemCopy<T> {
inner: ManuallyDrop<SliceDropGuard<T>>,
fat: *mut [MaybeUninit<T>],
}
impl<T> DropGuardElemCopy<T> {
#[inline(always)]
fn new(fat: *mut [MaybeUninit<T>], raw: *mut MaybeUninit<T>) -> Self {
Self {
inner: ManuallyDrop::new(SliceDropGuard::new(raw)),
fat,
}
}
}
impl<T> Drop for DropGuardElemCopy<T> {
#[inline]
fn drop(&mut self) {
unsafe {
ManuallyDrop::drop(&mut self.inner);
}
let container = unsafe { $target::from_raw(self.fat) };
drop(container);
}
}
let len = Len::read::<T::Dst>(reader)?;
let mem = $target::<[T::Dst]>::new_uninit_slice(len);
let fat = $target::into_raw(mem) as *mut [MaybeUninit<T::Dst>];
match T::TYPE_META {
TypeMeta::Static {
zero_copy: true, ..
} => {
let guard = DropGuardRawCopy(fat);
let dst = unsafe { &mut *fat };
unsafe { reader.copy_into_slice_t(dst)? };
mem::forget(guard);
}
TypeMeta::Static {
size,
zero_copy: false,
} => {
let raw_base = unsafe { (*fat).as_mut_ptr() };
let mut guard: DropGuardElemCopy<T::Dst> =
DropGuardElemCopy::new(fat, raw_base);
#[allow(clippy::arithmetic_side_effects)]
let reader = &mut unsafe { reader.as_trusted_for(size * len) }?;
for i in 0..len {
let slot = unsafe { &mut *raw_base.add(i) };
T::read(reader, slot)?;
guard.inner.inc_len();
}
mem::forget(guard);
}
TypeMeta::Dynamic => {
let raw_base = unsafe { (*fat).as_mut_ptr() };
let mut guard: DropGuardElemCopy<T::Dst> =
DropGuardElemCopy::new(fat, raw_base);
for i in 0..len {
let slot = unsafe { &mut *raw_base.add(i) };
T::read(reader, slot)?;
guard.inner.inc_len();
}
mem::forget(guard);
}
}
let container = unsafe { $target::from_raw(fat) };
let container = unsafe { container.assume_init() };
dst.write(container);
Ok(())
}
}
};
}
impl_heap_slice!(Box => AllocBox);
impl_heap_slice!(Rc => AllocRc);
impl_heap_slice!(Arc => AllocArc);
#[cfg(feature = "alloc")]
impl<T, Len> SchemaWrite for VecDeque<T, Len>
where
Len: SeqLen,
T: SchemaWrite,
T::Src: Sized,
{
type Src = collections::VecDeque<T::Src>;
#[inline(always)]
fn size_of(value: &Self::Src) -> WriteResult<usize> {
size_of_elem_iter::<T, Len>(value.iter())
}
#[inline(always)]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
if let TypeMeta::Static {
size,
zero_copy: true,
} = T::TYPE_META
{
#[allow(clippy::arithmetic_side_effects)]
let needed = Len::write_bytes_needed(src.len())? + src.len() * size;
let writer = &mut unsafe { writer.as_trusted_for(needed) }?;
Len::write(writer, src.len())?;
let (front, back) = src.as_slices();
unsafe {
writer.write_slice_t(front)?;
writer.write_slice_t(back)?;
}
writer.finish()?;
return Ok(());
}
write_elem_iter::<T, Len>(writer, src.iter())
}
}
#[cfg(feature = "alloc")]
impl<'de, T, Len> SchemaRead<'de> for VecDeque<T, Len>
where
Len: SeqLen,
T: SchemaRead<'de>,
{
type Dst = collections::VecDeque<T::Dst>;
#[inline(always)]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let vec = <Vec<T, Len>>::get(reader)?;
dst.write(vec.into());
Ok(())
}
}
#[cfg(feature = "alloc")]
pub struct BinaryHeap<T, Len = BincodeLen>(PhantomData<Len>, PhantomData<T>);
#[cfg(feature = "alloc")]
impl<T, Len> SchemaWrite for BinaryHeap<T, Len>
where
Len: SeqLen,
T: SchemaWrite,
T::Src: Sized,
{
type Src = collections::BinaryHeap<T::Src>;
#[inline(always)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
size_of_elem_slice::<T, Len>(src.as_slice())
}
#[inline(always)]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
write_elem_slice::<T, Len>(writer, src.as_slice())
}
}
#[cfg(feature = "alloc")]
impl<'de, T, Len> SchemaRead<'de> for BinaryHeap<T, Len>
where
Len: SeqLen,
T: SchemaRead<'de>,
T::Dst: Ord,
{
type Dst = collections::BinaryHeap<T::Dst>;
#[inline(always)]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let vec = <Vec<T, Len>>::get(reader)?;
dst.write(collections::BinaryHeap::from(vec));
Ok(())
}
}
#[cfg(feature = "bytes")]
impl<Len> SchemaWrite for Bytes<Len>
where
Len: SeqLen,
{
type Src = bytes::Bytes;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(Len::write_bytes_needed(src.len())? + src.len())
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
Len::write(writer, src.len())?;
writer.write(src.as_ref())?;
Ok(())
}
}
#[cfg(feature = "bytes")]
impl<'de, Len> SchemaRead<'de> for Bytes<Len>
where
Len: SeqLen,
{
type Dst = bytes::Bytes;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = Len::read::<u8>(reader)?;
let bytes = reader.fill_exact(len)?.to_vec();
unsafe { reader.consume_unchecked(len) };
dst.write(bytes::Bytes::from(bytes));
Ok(())
}
}
#[cfg(feature = "bytes")]
impl<Len> SchemaWrite for BytesMut<Len>
where
Len: SeqLen,
{
type Src = bytes::BytesMut;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(Len::write_bytes_needed(src.len())? + src.len())
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
Len::write(writer, src.len())?;
writer.write(src.as_ref())?;
Ok(())
}
}
#[cfg(feature = "bytes")]
impl<'de, Len> SchemaRead<'de> for BytesMut<Len>
where
Len: SeqLen,
{
type Dst = bytes::BytesMut;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = Len::read::<u8>(reader)?;
let bytes = reader.fill_exact(len)?.to_vec();
unsafe { reader.consume_unchecked(len) };
dst.write(bytes::BytesMut::from(bytes.as_slice()));
Ok(())
}
}