#[cfg(feature = "std")]
use std::{
collections::{HashMap, HashSet},
hash::Hash,
};
use {
crate::{
containers::SliceDropGuard,
error::{
invalid_bool_encoding, invalid_char_lead, invalid_tag_encoding, invalid_utf8_encoding,
pointer_sized_decode_error, read_length_encoding_overflow, unaligned_pointer_read,
ReadResult, WriteResult,
},
io::{Reader, Writer},
len::{BincodeLen, SeqLen},
schema::{size_of_elem_slice, write_elem_slice, SchemaRead, SchemaWrite, ZeroCopy},
TypeMeta,
},
core::{
marker::PhantomData,
mem::{self, transmute, MaybeUninit},
},
};
#[cfg(feature = "alloc")]
use {
crate::{
containers::{self},
error::WriteError,
schema::{size_of_elem_iter, write_elem_iter},
},
alloc::{
boxed::Box,
collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
rc::Rc,
string::String,
sync::Arc,
vec::Vec,
},
};
macro_rules! impl_int {
($type:ty, zero_copy: $zero_copy:expr) => {
impl SchemaWrite for $type {
type Src = $type;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<$type>(),
#[cfg(target_endian = "little")]
zero_copy: true,
#[cfg(not(target_endian = "little"))]
zero_copy: $zero_copy,
};
#[inline(always)]
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(size_of::<$type>())
}
#[inline(always)]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
Ok(writer.write(&src.to_le_bytes())?)
}
}
impl<'de> SchemaRead<'de> for $type {
type Dst = $type;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<$type>(),
#[cfg(target_endian = "little")]
zero_copy: true,
#[cfg(not(target_endian = "little"))]
zero_copy: $zero_copy,
};
#[inline(always)]
fn read(
reader: &mut impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let bytes = reader.fill_array::<{ size_of::<$type>() }>()?;
dst.write(<$type>::from_le_bytes(*bytes));
unsafe { reader.consume_unchecked(size_of::<$type>()) };
Ok(())
}
}
};
($type:ty as $cast:ty) => {
impl SchemaWrite for $type {
type Src = $type;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<$cast>(),
zero_copy: false,
};
#[inline]
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(size_of::<$cast>())
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
let src = *src as $cast;
Ok(writer.write(&src.to_le_bytes())?)
}
}
impl<'de> SchemaRead<'de> for $type {
type Dst = $type;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<$cast>(),
zero_copy: false,
};
#[inline]
fn read(
reader: &mut impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let casted = <$cast>::get(reader)?;
let val = casted
.try_into()
.map_err(|_| pointer_sized_decode_error())?;
dst.write(val);
Ok(())
}
}
};
}
unsafe impl ZeroCopy for u8 {}
unsafe impl ZeroCopy for i8 {}
macro_rules! impl_numeric_zero_copy {
($($ty:ty),+ $(,)?) => {
$(
unsafe impl ZeroCopy for $ty {}
)+
};
}
#[cfg(target_endian = "little")]
impl_numeric_zero_copy!(u16, i16, u32, i32, u64, i64, u128, i128, f32, f64);
impl_int!(u8, zero_copy: true);
impl_int!(i8, zero_copy: true);
impl_int!(u16, zero_copy: false);
impl_int!(i16, zero_copy: false);
impl_int!(u32, zero_copy: false);
impl_int!(i32, zero_copy: false);
impl_int!(u64, zero_copy: false);
impl_int!(i64, zero_copy: false);
impl_int!(u128, zero_copy: false);
impl_int!(i128, zero_copy: false);
impl_int!(f32, zero_copy: false);
impl_int!(f64, zero_copy: false);
impl_int!(usize as u64);
impl_int!(isize as i64);
impl SchemaWrite for bool {
type Src = bool;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<bool>(),
zero_copy: false,
};
#[inline]
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(size_of::<u8>())
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
unsafe { Ok(writer.write_t(&(*src as u8))?) }
}
}
impl<'de> SchemaRead<'de> for bool {
type Dst = bool;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<bool>(),
zero_copy: false,
};
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let byte = u8::get(reader)?;
match byte {
0 => {
dst.write(false);
}
1 => {
dst.write(true);
}
_ => return Err(invalid_bool_encoding(byte)),
}
Ok(())
}
}
impl SchemaWrite for char {
type Src = char;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
let mut buf = [0; 4];
let str = src.encode_utf8(&mut buf);
Ok(str.len())
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
let mut buf = [0; 4];
let str = src.encode_utf8(&mut buf);
writer.write(str.as_bytes())?;
Ok(())
}
}
impl<'de> SchemaRead<'de> for char {
type Dst = char;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let b0 = *reader.peek()?;
let len = match b0 {
0x00..=0x7F => 1,
0xC2..=0xDF => 2,
0xE0..=0xEF => 3,
0xF0..=0xF4 => 4,
_ => return Err(invalid_char_lead(b0)),
};
if len == 1 {
unsafe { reader.consume_unchecked(1) };
dst.write(b0 as char);
return Ok(());
}
let buf = reader.fill_exact(len)?;
let str = core::str::from_utf8(buf).map_err(invalid_utf8_encoding)?;
let c = str.chars().next().unwrap();
unsafe { reader.consume_unchecked(len) };
dst.write(c);
Ok(())
}
}
impl<T> SchemaWrite for PhantomData<T> {
type Src = PhantomData<T>;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 0,
zero_copy: true,
};
#[inline]
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(0)
}
#[inline]
fn write(_writer: &mut impl Writer, _src: &Self::Src) -> WriteResult<()> {
Ok(())
}
}
impl<'de, T> SchemaRead<'de> for PhantomData<T> {
type Dst = PhantomData<T>;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 0,
zero_copy: true,
};
#[inline]
fn read(_reader: &mut impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
Ok(())
}
}
impl SchemaWrite for () {
type Src = ();
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 0,
zero_copy: true,
};
#[inline]
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(0)
}
#[inline]
fn write(_writer: &mut impl Writer, _src: &Self::Src) -> WriteResult<()> {
Ok(())
}
}
impl<'de> SchemaRead<'de> for () {
type Dst = ();
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 0,
zero_copy: true,
};
#[inline]
fn read(_reader: &mut impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
Ok(())
}
}
#[cfg(feature = "alloc")]
impl<T> SchemaWrite for Vec<T>
where
T: SchemaWrite,
T::Src: Sized,
{
type Src = Vec<T::Src>;
#[inline]
fn size_of(value: &Self::Src) -> WriteResult<usize> {
<containers::Vec<T, BincodeLen<{ 1 << 27 }>>>::size_of(value)
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::Vec<T, BincodeLen<{ 1 << 27 }>>>::write(writer, value)
}
}
#[cfg(feature = "alloc")]
impl<'de, T> SchemaRead<'de> for Vec<T>
where
T: SchemaRead<'de>,
{
type Dst = Vec<T::Dst>;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::Vec<T, BincodeLen<{ 1 << 27 }>>>::read(reader, dst)
}
}
#[cfg(feature = "alloc")]
impl<T> SchemaWrite for VecDeque<T>
where
T: SchemaWrite,
T::Src: Sized,
{
type Src = VecDeque<T::Src>;
#[inline]
fn size_of(value: &Self::Src) -> WriteResult<usize> {
<containers::VecDeque<T, BincodeLen>>::size_of(value)
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::VecDeque<T, BincodeLen>>::write(writer, value)
}
}
#[cfg(feature = "alloc")]
impl<'de, T> SchemaRead<'de> for VecDeque<T>
where
T: SchemaRead<'de>,
{
type Dst = VecDeque<T::Dst>;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::VecDeque<T, BincodeLen>>::read(reader, dst)
}
}
impl<T> SchemaWrite for [T]
where
T: SchemaWrite,
T::Src: Sized,
{
type Src = [T::Src];
#[inline]
fn size_of(value: &Self::Src) -> WriteResult<usize> {
size_of_elem_slice::<T, BincodeLen>(value)
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
write_elem_slice::<T, BincodeLen>(writer, value)
}
}
unsafe impl<const N: usize, T> ZeroCopy for [T; N] where T: ZeroCopy {}
impl<'de, T, const N: usize> SchemaRead<'de> for [T; N]
where
T: SchemaRead<'de>,
{
type Dst = [T::Dst; N];
const TYPE_META: TypeMeta = const {
match T::TYPE_META {
TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
size: N * size,
zero_copy,
},
TypeMeta::Dynamic => TypeMeta::Dynamic,
}
};
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
if let TypeMeta::Static {
zero_copy: true, ..
} = T::TYPE_META
{
unsafe { reader.copy_into_t(dst)? };
return Ok(());
}
let dst =
unsafe { transmute::<&mut MaybeUninit<Self::Dst>, &mut [MaybeUninit<T::Dst>; N]>(dst) };
let base = dst.as_mut_ptr();
let mut guard = SliceDropGuard::<T::Dst>::new(base);
if let TypeMeta::Static { size, .. } = Self::TYPE_META {
let reader = &mut unsafe { reader.as_trusted_for(size) }?;
for i in 0..N {
let slot = unsafe { &mut *base.add(i) };
T::read(reader, slot)?;
guard.inc_len();
}
} else {
for i in 0..N {
let slot = unsafe { &mut *base.add(i) };
T::read(reader, slot)?;
guard.inc_len();
}
}
mem::forget(guard);
Ok(())
}
}
impl<T, const N: usize> SchemaWrite for [T; N]
where
T: SchemaWrite,
T::Src: Sized,
{
type Src = [T::Src; N];
const TYPE_META: TypeMeta = const {
match T::TYPE_META {
TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
size: N * size,
zero_copy,
},
TypeMeta::Dynamic => TypeMeta::Dynamic,
}
};
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(value: &Self::Src) -> WriteResult<usize> {
if let TypeMeta::Static { size, .. } = Self::TYPE_META {
return Ok(size);
}
value
.iter()
.map(T::size_of)
.try_fold(0usize, |acc, x| x.map(|x| acc + x))
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
match Self::TYPE_META {
TypeMeta::Static {
zero_copy: true, ..
} => {
unsafe { writer.write_slice_t(value)? };
}
TypeMeta::Static {
size,
zero_copy: false,
} => {
let writer = &mut unsafe { writer.as_trusted_for(size) }?;
for item in value {
T::write(writer, item)?;
}
writer.finish()?;
}
TypeMeta::Dynamic => {
for item in value {
T::write(writer, item)?;
}
}
}
Ok(())
}
}
impl<'de, T> SchemaRead<'de> for Option<T>
where
T: SchemaRead<'de>,
{
type Dst = Option<T::Dst>;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let variant = u8::get(reader)?;
match variant {
0 => dst.write(Option::None),
1 => dst.write(Option::Some(T::get(reader)?)),
_ => return Err(invalid_tag_encoding(variant as usize)),
};
Ok(())
}
}
impl<T> SchemaWrite for Option<T>
where
T: SchemaWrite,
T::Src: Sized,
{
type Src = Option<T::Src>;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
match src {
Option::Some(value) => Ok(1 + T::size_of(value)?),
Option::None => Ok(1),
}
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
match value {
Option::Some(value) => {
u8::write(writer, &1)?;
T::write(writer, value)
}
Option::None => u8::write(writer, &0),
}
}
}
impl<'de, T, E> SchemaRead<'de> for Result<T, E>
where
T: SchemaRead<'de>,
E: SchemaRead<'de>,
{
type Dst = Result<T::Dst, E::Dst>;
const TYPE_META: TypeMeta = match (T::TYPE_META, E::TYPE_META) {
(TypeMeta::Static { size: t_size, .. }, TypeMeta::Static { size: e_size, .. })
if t_size == e_size =>
{
TypeMeta::Static {
size: size_of::<u32>() + t_size,
zero_copy: false,
}
}
_ => TypeMeta::Dynamic,
};
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let variant = u32::get(reader)?;
match variant {
0 => dst.write(Result::Ok(T::get(reader)?)),
1 => dst.write(Result::Err(E::get(reader)?)),
_ => return Err(invalid_tag_encoding(variant as usize)),
};
Ok(())
}
}
impl<T, E> SchemaWrite for Result<T, E>
where
T: SchemaWrite,
E: SchemaWrite,
T::Src: Sized,
E::Src: Sized,
{
type Src = Result<T::Src, E::Src>;
const TYPE_META: TypeMeta = match (T::TYPE_META, E::TYPE_META) {
(TypeMeta::Static { size: t_size, .. }, TypeMeta::Static { size: e_size, .. })
if t_size == e_size =>
{
TypeMeta::Static {
size: size_of::<u32>() + t_size,
zero_copy: false,
}
}
_ => TypeMeta::Dynamic,
};
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
match src {
Result::Ok(value) => Ok(size_of::<u32>() + T::size_of(value)?),
Result::Err(error) => Ok(size_of::<u32>() + E::size_of(error)?),
}
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
match value {
Result::Ok(value) => {
u32::write(writer, &0)?;
T::write(writer, value)
}
Result::Err(error) => {
u32::write(writer, &1)?;
E::write(writer, error)
}
}
}
}
impl<'a, T> SchemaWrite for &'a T
where
T: SchemaWrite,
T: ?Sized,
{
type Src = &'a 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, value: &Self::Src) -> WriteResult<()> {
T::write(writer, *value)
}
}
macro_rules! impl_heap_container {
($container:ident) => {
#[cfg(feature = "alloc")]
impl<T> SchemaWrite for $container<T>
where
T: SchemaWrite,
{
type Src = $container<T::Src>;
const TYPE_META: TypeMeta = const {
match T::TYPE_META {
TypeMeta::Static { size, .. } => TypeMeta::Static {
size,
zero_copy: false,
},
TypeMeta::Dynamic => TypeMeta::Dynamic,
}
};
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
T::size_of(src)
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
T::write(writer, value)
}
}
#[cfg(feature = "alloc")]
impl<'de, T> SchemaRead<'de> for $container<T>
where
T: SchemaRead<'de>,
{
type Dst = $container<T::Dst>;
const TYPE_META: TypeMeta = const {
match T::TYPE_META {
TypeMeta::Static { size, .. } => TypeMeta::Static {
size,
zero_copy: false,
},
TypeMeta::Dynamic => TypeMeta::Dynamic,
}
};
#[inline]
fn read(
reader: &mut impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
struct DropGuard<T>(*mut MaybeUninit<T>);
impl<T> Drop for DropGuard<T> {
#[inline]
fn drop(&mut self) {
drop(unsafe { $container::from_raw(self.0) });
}
}
let mem = $container::<T::Dst>::new_uninit();
let ptr = $container::into_raw(mem) as *mut _;
let guard: DropGuard<T::Dst> = DropGuard(ptr);
T::read(reader, unsafe { &mut *ptr })?;
mem::forget(guard);
unsafe {
dst.write($container::from_raw(ptr).assume_init());
}
Ok(())
}
}
};
}
impl_heap_container!(Box);
impl_heap_container!(Rc);
impl_heap_container!(Arc);
#[cfg(feature = "alloc")]
impl<T> SchemaWrite for Box<[T]>
where
T: SchemaWrite,
T::Src: Sized,
{
type Src = Box<[T::Src]>;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::Box<[T], BincodeLen>>::size_of(src)
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::Box<[T], BincodeLen>>::write(writer, value)
}
}
#[cfg(feature = "alloc")]
impl<T> SchemaWrite for Rc<[T]>
where
T: SchemaWrite,
T::Src: Sized,
{
type Src = Rc<[T::Src]>;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::Rc<[T], BincodeLen>>::size_of(src)
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::Rc<[T], BincodeLen>>::write(writer, value)
}
}
#[cfg(feature = "alloc")]
impl<T> SchemaWrite for Arc<[T]>
where
T: SchemaWrite,
T::Src: Sized,
{
type Src = Arc<[T::Src]>;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::Arc<[T], BincodeLen>>::size_of(src)
}
#[inline]
fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::Arc<[T], BincodeLen>>::write(writer, value)
}
}
#[cfg(feature = "alloc")]
impl<'de, T> SchemaRead<'de> for Box<[T]>
where
T: SchemaRead<'de>,
{
type Dst = Box<[T::Dst]>;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::Box<[T], BincodeLen>>::read(reader, dst)
}
}
#[cfg(feature = "alloc")]
impl<'de, T> SchemaRead<'de> for Rc<[T]>
where
T: SchemaRead<'de>,
{
type Dst = Rc<[T::Dst]>;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::Rc<[T], BincodeLen>>::read(reader, dst)
}
}
#[cfg(feature = "alloc")]
impl<'de, T> SchemaRead<'de> for Arc<[T]>
where
T: SchemaRead<'de>,
{
type Dst = Arc<[T::Dst]>;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::Arc<[T], BincodeLen>>::read(reader, dst)
}
}
impl SchemaWrite for str {
type Src = str;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(<BincodeLen>::write_bytes_needed(src.len())? + src.len())
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
<BincodeLen>::write(writer, src.len())?;
writer.write(src.as_bytes())?;
Ok(())
}
}
#[cfg(feature = "alloc")]
impl SchemaWrite for String {
type Src = String;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<str>::size_of(src)
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
<str>::write(writer, src)
}
}
impl<'de> SchemaRead<'de> for &'de str {
type Dst = &'de str;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = <BincodeLen>::read::<u8>(reader)?;
let bytes = reader.borrow_exact(len)?;
match core::str::from_utf8(bytes) {
Ok(s) => {
dst.write(s);
Ok(())
}
Err(e) => Err(invalid_utf8_encoding(e)),
}
}
}
#[cfg(feature = "alloc")]
impl<'de> SchemaRead<'de> for String {
type Dst = String;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = <BincodeLen>::read::<u8>(reader)?;
let bytes = reader.fill_exact(len)?.to_vec();
unsafe { reader.consume_unchecked(len) };
match String::from_utf8(bytes) {
Ok(s) => {
dst.write(s);
Ok(())
}
Err(e) => Err(invalid_utf8_encoding(e.utf8_error())),
}
}
}
#[cfg(feature = "bytes")]
impl SchemaWrite for bytes::Bytes {
type Src = bytes::Bytes;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::Bytes<BincodeLen>>::size_of(src)
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
<containers::Bytes<BincodeLen>>::write(writer, src)
}
}
#[cfg(feature = "bytes")]
impl<'de> SchemaRead<'de> for bytes::Bytes {
type Dst = bytes::Bytes;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::Bytes<BincodeLen>>::read(reader, dst)
}
}
#[cfg(feature = "bytes")]
impl SchemaWrite for bytes::BytesMut {
type Src = bytes::BytesMut;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::BytesMut<BincodeLen>>::size_of(src)
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
<containers::BytesMut<BincodeLen>>::write(writer, src)
}
}
#[cfg(feature = "bytes")]
impl<'de> SchemaRead<'de> for bytes::BytesMut {
type Dst = bytes::BytesMut;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::BytesMut<BincodeLen>>::read(reader, dst)
}
}
macro_rules! impl_seq {
($feature: literal, $target: ident<$key: ident : $($constraint:path)|*, $value: ident>, $with_capacity: expr) => {
#[cfg(feature = $feature)]
impl<$key, $value> SchemaWrite for $target<$key, $value>
where
$key: SchemaWrite,
$key::Src: Sized,
$value: SchemaWrite,
$value::Src: Sized,
{
type Src = $target<$key::Src, $value::Src>;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
if let (TypeMeta::Static { size: key_size, .. }, TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
return Ok(<BincodeLen>::write_bytes_needed(src.len())? + (key_size + value_size) * src.len());
}
Ok(<BincodeLen>::write_bytes_needed(src.len())? +
src
.iter()
.try_fold(
0usize,
|acc, (k, v)|
Ok::<_, WriteError>(
acc
+ $key::size_of(k)?
+ $value::size_of(v)?
)
)?
)
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
if let (TypeMeta::Static { size: key_size, .. }, TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
let len = src.len();
#[allow(clippy::arithmetic_side_effects)]
let needed = <BincodeLen>::write_bytes_needed(len)? + (key_size + value_size) * len;
let writer = &mut unsafe { writer.as_trusted_for(needed) }?;
<BincodeLen>::write(writer, len)?;
for (k, v) in src.iter() {
$key::write(writer, k)?;
$value::write(writer, v)?;
}
writer.finish()?;
return Ok(());
}
<BincodeLen>::write(writer, src.len())?;
for (k, v) in src.iter() {
$key::write(writer, k)?;
$value::write(writer, v)?;
}
Ok(())
}
}
#[cfg(feature = $feature)]
impl<'de, $key, $value> SchemaRead<'de> for $target<$key, $value>
where
$key: SchemaRead<'de>,
$value: SchemaRead<'de>
$(,$key::Dst: $constraint+)*,
{
type Dst = $target<$key::Dst, $value::Dst>;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = <BincodeLen>::read::<($key::Dst, $value::Dst)>(reader)?;
let map = if let (TypeMeta::Static { size: key_size, .. }, TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
#[allow(clippy::arithmetic_side_effects)]
let reader = &mut unsafe { reader.as_trusted_for((key_size + value_size) * len) }?;
let mut map = $with_capacity(len);
for _ in 0..len {
let k = $key::get(reader)?;
let v = $value::get(reader)?;
map.insert(k, v);
}
map
} else {
let mut map = $with_capacity(len);
for _ in 0..len {
let k = $key::get(reader)?;
let v = $value::get(reader)?;
map.insert(k, v);
}
map
};
dst.write(map);
Ok(())
}
}
};
($feature: literal, $target: ident <$key: ident : $($constraint:path)|*>, $with_capacity: expr, $insert: ident) => {
#[cfg(feature = $feature)]
impl<$key: SchemaWrite> SchemaWrite for $target<$key>
where
$key::Src: Sized,
{
type Src = $target<$key::Src>;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
size_of_elem_iter::<$key, BincodeLen>(src.iter())
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
write_elem_iter::<$key, BincodeLen>(writer, src.iter())
}
}
#[cfg(feature = $feature)]
impl<'de, $key> SchemaRead<'de> for $target<$key>
where
$key: SchemaRead<'de>
$(,$key::Dst: $constraint+)*,
{
type Dst = $target<$key::Dst>;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = <BincodeLen>::read::<$key::Dst>(reader)?;
let map = match $key::TYPE_META {
TypeMeta::Static { size, .. } => {
#[allow(clippy::arithmetic_side_effects)]
let reader = &mut unsafe { reader.as_trusted_for(size * len) }?;
let mut set = $with_capacity(len);
for _ in 0..len {
set.$insert($key::get(reader)?);
}
set
}
TypeMeta::Dynamic => {
let mut set = $with_capacity(len);
for _ in 0..len {
set.$insert($key::get(reader)?);
}
set
}
};
dst.write(map);
Ok(())
}
}
};
}
impl_seq! { "alloc", BTreeMap<K: Ord, V>, |_| BTreeMap::new() }
impl_seq! { "std", HashMap<K: Hash | Eq, V>, HashMap::with_capacity }
impl_seq! { "alloc", BTreeSet<K: Ord>, |_| BTreeSet::new(), insert }
impl_seq! { "std", HashSet<K: Hash | Eq>, HashSet::with_capacity, insert }
impl_seq! { "alloc", LinkedList<K:>, |_| LinkedList::new(), push_back }
#[cfg(feature = "alloc")]
impl<T> SchemaWrite for BinaryHeap<T>
where
T: SchemaWrite,
T::Src: Sized,
{
type Src = BinaryHeap<T::Src>;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::BinaryHeap<T, BincodeLen>>::size_of(src)
}
#[inline]
fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
<containers::BinaryHeap<T, BincodeLen>>::write(writer, src)
}
}
#[cfg(feature = "alloc")]
impl<'de, T> SchemaRead<'de> for BinaryHeap<T>
where
T: SchemaRead<'de>,
T::Dst: Ord,
{
type Dst = BinaryHeap<T::Dst>;
#[inline]
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::BinaryHeap<T, BincodeLen>>::read(reader, dst)
}
}
mod zero_copy {
use {
super::*,
core::slice::{from_raw_parts, from_raw_parts_mut},
};
#[inline(always)]
fn cast_ensure_aligned<T, U>(ptr: *const T) -> ReadResult<*const U> {
let ptr = ptr.cast::<U>();
if align_of::<U>() > 1 && !ptr.is_aligned() {
return Err(unaligned_pointer_read());
}
Ok(ptr)
}
#[inline(always)]
fn cast_ensure_aligned_mut<T, U>(ptr: *mut T) -> ReadResult<*mut U> {
let ptr = ptr.cast::<U>();
if align_of::<U>() > 1 && !ptr.is_aligned() {
return Err(unaligned_pointer_read());
}
Ok(ptr)
}
#[inline(always)]
pub(super) unsafe fn cast_slice_to_t<T>(bytes: &[u8]) -> ReadResult<&T> {
debug_assert_eq!(bytes.len(), size_of::<T>());
let ptr = cast_ensure_aligned::<u8, T>(bytes.as_ptr())?;
let val = unsafe { &*ptr };
Ok(val)
}
#[inline(always)]
pub(super) unsafe fn cast_slice_to_t_mut<T>(bytes: &mut [u8]) -> ReadResult<&mut T> {
debug_assert_eq!(bytes.len(), size_of::<T>());
let ptr = cast_ensure_aligned_mut::<u8, T>(bytes.as_mut_ptr())?;
let val = unsafe { &mut *ptr };
Ok(val)
}
#[inline(always)]
pub(super) unsafe fn cast_slice_to_slice_t<T>(bytes: &[u8], len: usize) -> ReadResult<&[T]> {
debug_assert_eq!(Some(bytes.len()), len.checked_mul(size_of::<T>()));
let ptr = cast_ensure_aligned::<u8, T>(bytes.as_ptr())?;
let slice = unsafe { from_raw_parts(ptr, len) };
Ok(slice)
}
#[inline(always)]
pub(super) unsafe fn cast_slice_to_slice_t_mut<T>(
bytes: &mut [u8],
len: usize,
) -> ReadResult<&mut [T]> {
debug_assert_eq!(Some(bytes.len()), len.checked_mul(size_of::<T>()));
let ptr = cast_ensure_aligned_mut::<u8, T>(bytes.as_mut_ptr())?;
let slice = unsafe { from_raw_parts_mut(ptr, len) };
Ok(slice)
}
pub(super) const fn type_meta_t<'de, T>() -> TypeMeta
where
T: SchemaRead<'de> + ZeroCopy,
{
match T::TYPE_META {
TypeMeta::Static {
size,
zero_copy: true,
} => TypeMeta::Static {
size,
zero_copy: false,
},
_ => panic!("Type is not zero-copy"),
}
}
pub(super) const fn type_meta_slice<'de, T>() -> TypeMeta
where
T: SchemaRead<'de> + ZeroCopy,
{
match T::TYPE_META {
TypeMeta::Static {
zero_copy: true, ..
} => TypeMeta::Dynamic,
_ => panic!("Type is not zero-copy"),
}
}
#[inline(always)]
pub(super) fn read_slice_len_checked<'de>(
reader: &mut impl Reader<'de>,
size: usize,
) -> ReadResult<(usize, usize)> {
let Ok(len): Result<usize, _> = u64::get(reader)?.try_into() else {
return Err(pointer_sized_decode_error());
};
let Some(total_size) = len.checked_mul(size) else {
return Err(read_length_encoding_overflow("usize::MAX"));
};
Ok((len, total_size))
}
}
impl<'de, T> SchemaRead<'de> for &'de T
where
T: SchemaRead<'de> + ZeroCopy,
{
type Dst = &'de T::Dst;
const TYPE_META: TypeMeta = zero_copy::type_meta_t::<T>();
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let size = T::TYPE_META.size_assert_zero_copy();
let bytes = reader.borrow_exact(size)?;
let val = unsafe { zero_copy::cast_slice_to_t::<T::Dst>(bytes)? };
dst.write(val);
Ok(())
}
}
impl<'de, T> SchemaRead<'de> for &'de mut T
where
T: SchemaRead<'de> + ZeroCopy,
{
type Dst = &'de mut T::Dst;
const TYPE_META: TypeMeta = zero_copy::type_meta_t::<T>();
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let size = T::TYPE_META.size_assert_zero_copy();
let bytes = reader.borrow_exact_mut(size)?;
let val = unsafe { zero_copy::cast_slice_to_t_mut::<T::Dst>(bytes)? };
dst.write(val);
Ok(())
}
}
impl<'de, T> SchemaRead<'de> for &'de [T]
where
T: SchemaRead<'de> + ZeroCopy,
{
type Dst = &'de [T::Dst];
const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T>();
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let size = T::TYPE_META.size_assert_zero_copy();
let (len, total_size) = zero_copy::read_slice_len_checked(reader, size)?;
let bytes = reader.borrow_exact(total_size)?;
let slice = unsafe { zero_copy::cast_slice_to_slice_t::<T::Dst>(bytes, len)? };
dst.write(slice);
Ok(())
}
}
impl<'de, T> SchemaRead<'de> for &'de mut [T]
where
T: SchemaRead<'de> + ZeroCopy,
{
type Dst = &'de mut [T::Dst];
const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T>();
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let size = T::TYPE_META.size_assert_zero_copy();
let (len, total_size) = zero_copy::read_slice_len_checked(reader, size)?;
let bytes = reader.borrow_exact_mut(total_size)?;
let slice = unsafe { zero_copy::cast_slice_to_slice_t_mut::<T::Dst>(bytes, len)? };
dst.write(slice);
Ok(())
}
}