#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::borrow::ToOwned;
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
use alloc::sync::Arc;
use {
crate::{
TypeMeta,
config::{Config, ConfigCore, ZeroCopy},
containers::decode_into_slice_t,
context,
error::{
ReadResult, WriteResult, invalid_bool_encoding, invalid_char_lead,
invalid_tag_encoding, invalid_utf8_encoding, invalid_value, pointer_sized_decode_error,
read_length_encoding_overflow, unaligned_pointer_read,
},
int_encoding::{ByteOrder, Endian, IntEncoding, PlatformEndian},
io::{Reader, Writer},
len::SeqLen,
schema::{
SchemaRead, SchemaReadContext, SchemaWrite, size_of_elem_slice, write_elem_slice,
},
tag_encoding::TagEncoding,
},
core::{
marker::PhantomData,
mem::{MaybeUninit, transmute},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
num::{
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
},
ops::{Bound, Range, RangeInclusive},
time::Duration,
},
pastey::paste,
};
#[cfg(feature = "alloc")]
use {
crate::{containers, io::BorrowKind},
alloc::{
borrow::Cow,
boxed::Box,
collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
rc::Rc,
string::String,
vec::Vec,
},
core::mem,
};
#[cfg(feature = "std")]
use {
core::hash::{BuildHasher, Hash},
std::{
collections::{HashMap, HashSet},
time::{SystemTime, UNIX_EPOCH},
},
};
macro_rules! impl_int_config_dependent {
($($type:ty),*) => {
paste! {
$(
unsafe impl<C: ConfigCore> ZeroCopy<C> for $type where C::IntEncoding: ZeroCopy<C> {}
unsafe impl<C: ConfigCore> SchemaWrite<C> for $type {
type Src = $type;
const TYPE_META: TypeMeta = if C::IntEncoding::STATIC {
TypeMeta::Static {
size: size_of::<$type>(),
zero_copy: C::IntEncoding::ZERO_COPY,
}
} else {
TypeMeta::Dynamic
};
#[inline(always)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(C::IntEncoding::[<size_of_ $type>](*src))
}
#[inline(always)]
fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
C::IntEncoding::[<encode_ $type>](*src, writer)
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $type {
type Dst = $type;
const TYPE_META: TypeMeta = if C::IntEncoding::STATIC {
TypeMeta::Static {
size: size_of::<$type>(),
zero_copy: C::IntEncoding::ZERO_COPY,
}
} else {
TypeMeta::Dynamic
};
#[inline(always)]
fn read(
reader: impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let val = C::IntEncoding::[<decode_ $type>](reader)?;
dst.write(val);
Ok(())
}
}
)*
}
};
}
impl_int_config_dependent!(u16, u32, u64, u128, i16, i32, i64, i128);
macro_rules! impl_float {
($($ty:ty),*) => {
$(
unsafe impl<C: ConfigCore> ZeroCopy<C> for $ty where C::ByteOrder: PlatformEndian {}
unsafe impl<C: ConfigCore> SchemaWrite<C> for $ty {
type Src = $ty;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<$ty>(),
#[cfg(target_endian = "big")]
zero_copy: matches!(C::ByteOrder::ENDIAN, Endian::Big),
#[cfg(target_endian = "little")]
zero_copy: matches!(C::ByteOrder::ENDIAN, Endian::Little),
};
#[inline(always)]
fn size_of(_val: &Self::Src) -> WriteResult<usize> {
Ok(size_of::<$ty>())
}
#[inline(always)]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
let bytes = match C::ByteOrder::ENDIAN {
Endian::Big => src.to_be_bytes(),
Endian::Little => src.to_le_bytes(),
};
writer.write(&bytes)?;
Ok(())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $ty {
type Dst = $ty;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<$ty>(),
#[cfg(target_endian = "big")]
zero_copy: matches!(C::ByteOrder::ENDIAN, Endian::Big),
#[cfg(target_endian = "little")]
zero_copy: matches!(C::ByteOrder::ENDIAN, Endian::Little),
};
#[inline(always)]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let bytes = reader.take_array::<{ size_of::<$ty>() }>()?;
let val = match C::ByteOrder::ENDIAN {
Endian::Big => <$ty>::from_be_bytes(bytes),
Endian::Little => <$ty>::from_le_bytes(bytes),
};
dst.write(val);
Ok(())
}
}
)*
};
}
impl_float!(f32, f64);
macro_rules! impl_pointer_width {
($($type:ty => $target:ty),*) => {
$(
#[cfg(target_pointer_width = "64")]
unsafe impl<C: ConfigCore> ZeroCopy<C> for $type where C::IntEncoding: ZeroCopy<C> {}
unsafe impl<C: ConfigCore> SchemaWrite<C> for $type {
type Src = $type;
const TYPE_META: TypeMeta = if C::IntEncoding::STATIC {
TypeMeta::Static {
size: size_of::<$target>(),
#[cfg(target_pointer_width = "64")]
zero_copy: C::IntEncoding::ZERO_COPY,
#[cfg(not(target_pointer_width = "64"))]
zero_copy: false,
}
} else {
TypeMeta::Dynamic
};
#[inline(always)]
fn size_of(val: &Self::Src) -> WriteResult<usize> {
<$target as SchemaWrite<C>>::size_of(&(*val as $target))
}
#[inline(always)]
fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
<$target as SchemaWrite<C>>::write(writer, &(*src as $target))
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $type {
type Dst = $type;
const TYPE_META: TypeMeta = if C::IntEncoding::STATIC {
TypeMeta::Static {
size: size_of::<$target>(),
#[cfg(target_pointer_width = "64")]
zero_copy: C::IntEncoding::ZERO_COPY,
#[cfg(not(target_pointer_width = "64"))]
zero_copy: false,
}
} else {
TypeMeta::Dynamic
};
#[inline(always)]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let target = <$target as SchemaRead<C>>::get(reader)?;
let val = target.try_into().map_err(|_| pointer_sized_decode_error())?;
dst.write(val);
Ok(())
}
}
)*
};
}
impl_pointer_width!(usize => u64, isize => i64);
macro_rules! impl_byte {
($($type:ty),*) => {
$(
unsafe impl<C: ConfigCore> ZeroCopy<C> for $type {}
unsafe impl<C: ConfigCore> SchemaWrite<C> for $type {
type Src = $type;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<$type>(),
zero_copy: true,
};
#[inline(always)]
fn size_of(_val: &Self::Src) -> WriteResult<usize> {
Ok(size_of::<$type>())
}
#[inline(always)]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
writer.write(&[*src as u8])?;
Ok(())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $type {
type Dst = $type;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<$type>(),
zero_copy: true,
};
#[inline(always)]
fn read(
mut reader: impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let byte = reader.take_array::<{ 1 }>()?;
dst.write(byte[0] as $type);
Ok(())
}
}
)*
};
}
impl_byte!(u8, i8);
unsafe impl<C: ConfigCore> SchemaWrite<C> 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(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
unsafe { Ok(writer.write_t(&(*src as u8))?) }
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for bool {
type Dst = bool;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: size_of::<bool>(),
zero_copy: false,
};
#[inline]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let byte = <u8 as SchemaRead<'de, C>>::get(reader)?;
match byte {
0 => {
dst.write(false);
}
1 => {
dst.write(true);
}
_ => return Err(invalid_bool_encoding(byte)),
}
Ok(())
}
}
unsafe impl<C: ConfigCore> SchemaWrite<C> 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(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
let mut buf = [0; 4];
let str = src.encode_utf8(&mut buf);
writer.write(str.as_bytes())?;
Ok(())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for char {
type Dst = char;
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
use crate::error::ReadError;
#[cold]
fn utf8_error(buf: &[u8]) -> ReadError {
invalid_utf8_encoding(core::str::from_utf8(buf).unwrap_err())
}
let b0 = reader.take_byte()?;
let code_point = match b0 {
0x00..=0x7F => {
dst.write(b0 as char);
return Ok(());
}
0xC2..=0xDF => {
let b1 = reader.take_byte()?;
if (b1 & 0xC0) != 0x80 {
return Err(utf8_error(&[b0, b1]));
}
((b0 & 0x1F) as u32) << 6 | ((b1 & 0x3F) as u32)
}
0xE0..=0xEF => {
let [b1, b2] = reader.take_array()?;
if (b1 & 0xC0) != 0x80 || (b2 & 0xC0) != 0x80 {
return Err(utf8_error(&[b0, b1, b2]));
}
if (b0 == 0xE0 && b1 < 0xA0) || (b0 == 0xED && b1 >= 0xA0) {
return Err(utf8_error(&[b0, b1, b2]));
}
((b0 & 0x0F) as u32) << 12 | ((b1 & 0x3F) as u32) << 6 | ((b2 & 0x3F) as u32)
}
0xF0..=0xF4 => {
let [b1, b2, b3] = reader.take_array()?;
if (b1 & 0xC0) != 0x80 || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 {
return Err(utf8_error(&[b0, b1, b2, b3]));
}
if (b0 == 0xF0 && b1 < 0x90) || (b0 == 0xF4 && b1 > 0x8F) {
return Err(utf8_error(&[b0, b1, b2, b3]));
}
((b0 & 0x07) as u32) << 18
| ((b1 & 0x3F) as u32) << 12
| ((b2 & 0x3F) as u32) << 6
| ((b3 & 0x3F) as u32)
}
_ => return Err(invalid_char_lead(b0)),
};
let c = char::from_u32(code_point).ok_or(ReadError::InvalidUtf8Code(code_point))?;
dst.write(c);
Ok(())
}
}
unsafe impl<T, C: ConfigCore> SchemaWrite<C> 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: impl Writer, _src: &Self::Src) -> WriteResult<()> {
Ok(())
}
}
unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for PhantomData<T> {
type Dst = PhantomData<T>;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 0,
zero_copy: true,
};
#[inline]
fn read(_reader: impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
Ok(())
}
}
unsafe impl<C: ConfigCore> SchemaWrite<C> 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: impl Writer, _src: &Self::Src) -> WriteResult<()> {
Ok(())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for () {
type Dst = ();
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 0,
zero_copy: true,
};
#[inline]
fn read(_reader: impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
Ok(())
}
}
#[cfg(feature = "alloc")]
unsafe impl<T, C: Config> SchemaWrite<C> for Vec<T>
where
T: SchemaWrite<C>,
T::Src: Sized,
{
type Src = Vec<T::Src>;
#[inline]
fn size_of(value: &Self::Src) -> WriteResult<usize> {
<containers::Vec<T, C::LengthEncoding>>::size_of(value)
}
#[inline]
fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::Vec<T, C::LengthEncoding>>::write(writer, value)
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Vec<T>
where
T: SchemaRead<'de, C>,
{
type Dst = Vec<T::Dst>;
#[inline]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::Vec<T, C::LengthEncoding>>::read(reader, dst)
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, T, C: ConfigCore> SchemaReadContext<'de, C, context::Len> for Vec<T>
where
T: SchemaRead<'de, C>,
{
type Dst = Vec<T::Dst>;
#[inline]
fn read_with_context(
ctx: context::Len,
mut reader: impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let len = ctx.0;
let mut vec = Vec::with_capacity(len);
decode_into_slice_t::<T, C>(reader.by_ref(), &mut vec.spare_capacity_mut()[..len])?;
unsafe { vec.set_len(len) };
dst.write(vec);
Ok(())
}
}
#[cfg(feature = "alloc")]
unsafe impl<T, C: Config> SchemaWrite<C> for VecDeque<T>
where
T: SchemaWrite<C>,
T::Src: Sized,
{
type Src = VecDeque<T::Src>;
#[inline]
fn size_of(value: &Self::Src) -> WriteResult<usize> {
<containers::VecDeque<T, C::LengthEncoding>>::size_of(value)
}
#[inline]
fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::VecDeque<T, C::LengthEncoding>>::write(writer, value)
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for VecDeque<T>
where
T: SchemaRead<'de, C>,
{
type Dst = VecDeque<T::Dst>;
#[inline]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::VecDeque<T, C::LengthEncoding>>::read(reader, dst)
}
}
unsafe impl<T, C: Config> SchemaWrite<C> for [T]
where
T: SchemaWrite<C>,
T::Src: Sized,
{
type Src = [T::Src];
#[inline]
fn size_of(value: &Self::Src) -> WriteResult<usize> {
size_of_elem_slice::<T, C::LengthEncoding, C>(value)
}
#[inline]
fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
write_elem_slice::<T, C::LengthEncoding, C>(writer, value)
}
}
unsafe impl<const N: usize, C: ConfigCore, T> ZeroCopy<C> for [T; N] where T: ZeroCopy<C> {}
unsafe impl<'de, T, const N: usize, C: ConfigCore> SchemaRead<'de, C> for [T; N]
where
T: SchemaRead<'de, C>,
{
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: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let dst =
unsafe { transmute::<&mut MaybeUninit<Self::Dst>, &mut [MaybeUninit<T::Dst>; N]>(dst) };
decode_into_slice_t::<T, C>(reader, dst)
}
}
unsafe impl<T, const N: usize, C: ConfigCore> SchemaWrite<C> for [T; N]
where
T: SchemaWrite<C>,
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(mut writer: 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 mut writer = unsafe { writer.as_trusted_for(size) }?;
for item in value {
T::write(writer.by_ref(), item)?;
}
writer.finish()?;
}
TypeMeta::Dynamic => {
for item in value {
T::write(writer.by_ref(), item)?;
}
}
}
Ok(())
}
}
unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for Option<T>
where
T: SchemaRead<'de, C>,
{
type Dst = Option<T::Dst>;
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let variant = <u8 as SchemaRead<'de, C>>::get(reader.by_ref())?;
match variant {
0 => dst.write(Option::None),
1 => dst.write(Option::Some(T::get(reader)?)),
_ => return Err(invalid_tag_encoding(variant as usize)),
};
Ok(())
}
}
unsafe impl<T, C: ConfigCore> SchemaWrite<C> for Option<T>
where
T: SchemaWrite<C>,
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(mut writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
match value {
Option::Some(value) => {
<u8 as SchemaWrite<C>>::write(writer.by_ref(), &1)?;
T::write(writer, value)
}
Option::None => <u8 as SchemaWrite<C>>::write(writer, &0),
}
}
}
unsafe impl<'de, T, E, C: Config> SchemaRead<'de, C> for Result<T, E>
where
T: SchemaRead<'de, C>,
E: SchemaRead<'de, C>,
{
type Dst = Result<T::Dst, E::Dst>;
const TYPE_META: TypeMeta = match (
T::TYPE_META,
E::TYPE_META,
<C::TagEncoding as SchemaRead<C>>::TYPE_META,
) {
(
TypeMeta::Static { size: t_size, .. },
TypeMeta::Static { size: e_size, .. },
TypeMeta::Static {
size: disc_size, ..
},
) if t_size == e_size => TypeMeta::Static {
size: disc_size + t_size,
zero_copy: false,
},
_ => TypeMeta::Dynamic,
};
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let disc = C::TagEncoding::try_into_u32(C::TagEncoding::get(reader.by_ref())?)?;
match disc {
0 => dst.write(Result::Ok(T::get(reader)?)),
1 => dst.write(Result::Err(E::get(reader)?)),
_ => return Err(invalid_tag_encoding(disc as usize)),
};
Ok(())
}
}
unsafe impl<T, E, C: Config> SchemaWrite<C> for Result<T, E>
where
T: SchemaWrite<C>,
E: SchemaWrite<C>,
T::Src: Sized,
E::Src: Sized,
{
type Src = Result<T::Src, E::Src>;
const TYPE_META: TypeMeta = match (
T::TYPE_META,
E::TYPE_META,
<C::TagEncoding as SchemaWrite<C>>::TYPE_META,
) {
(
TypeMeta::Static { size: t_size, .. },
TypeMeta::Static { size: e_size, .. },
TypeMeta::Static {
size: disc_size, ..
},
) if t_size == e_size => TypeMeta::Static {
size: disc_size + 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(C::TagEncoding::size_of_from_u32(0)? + T::size_of(value)?),
Result::Err(error) => Ok(C::TagEncoding::size_of_from_u32(1)? + E::size_of(error)?),
}
}
#[inline]
fn write(mut writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
match value {
Result::Ok(value) => {
C::TagEncoding::write_from_u32(writer.by_ref(), 0)?;
T::write(writer, value)
}
Result::Err(error) => {
C::TagEncoding::write_from_u32(writer.by_ref(), 1)?;
E::write(writer, error)
}
}
}
}
unsafe impl<'a, T, C: ConfigCore> SchemaWrite<C> for &'a T
where
T: SchemaWrite<C>,
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: impl Writer, value: &Self::Src) -> WriteResult<()> {
T::write(writer, *value)
}
}
macro_rules! impl_heap_container {
($container:ident) => {
#[cfg(feature = "alloc")]
unsafe impl<T, C: ConfigCore> SchemaWrite<C> for $container<T>
where
T: SchemaWrite<C>,
{
type Src = $container<T::Src>;
const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
T::size_of(src)
}
#[inline]
fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
T::write(writer, value)
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for $container<T>
where
T: SchemaRead<'de, C>,
{
type Dst = $container<T::Dst>;
const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
#[inline]
fn read(reader: 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);
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
impl_heap_container!(Arc);
#[cfg(feature = "alloc")]
unsafe impl<T, C: Config> SchemaWrite<C> for Box<[T]>
where
T: SchemaWrite<C>,
T::Src: Sized,
{
type Src = Box<[T::Src]>;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::Box<[T], C::LengthEncoding>>::size_of(src)
}
#[inline]
fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::Box<[T], C::LengthEncoding>>::write(writer, value)
}
}
#[cfg(feature = "alloc")]
unsafe impl<T, C: Config> SchemaWrite<C> for Rc<[T]>
where
T: SchemaWrite<C>,
T::Src: Sized,
{
type Src = Rc<[T::Src]>;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::Rc<[T], C::LengthEncoding>>::size_of(src)
}
#[inline]
fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::Rc<[T], C::LengthEncoding>>::write(writer, value)
}
}
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
unsafe impl<T, C: Config> SchemaWrite<C> for Arc<[T]>
where
T: SchemaWrite<C>,
T::Src: Sized,
{
type Src = Arc<[T::Src]>;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::Arc<[T], C::LengthEncoding>>::size_of(src)
}
#[inline]
fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
<containers::Arc<[T], C::LengthEncoding>>::write(writer, value)
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Box<[T]>
where
T: SchemaRead<'de, C>,
{
type Dst = Box<[T::Dst]>;
#[inline]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::Box<[T], C::LengthEncoding>>::read(reader, dst)
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Rc<[T]>
where
T: SchemaRead<'de, C>,
{
type Dst = Rc<[T::Dst]>;
#[inline]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::Rc<[T], C::LengthEncoding>>::read(reader, dst)
}
}
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Arc<[T]>
where
T: SchemaRead<'de, C>,
{
type Dst = Arc<[T::Dst]>;
#[inline]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::Arc<[T], C::LengthEncoding>>::read(reader, dst)
}
}
unsafe impl<C: Config> SchemaWrite<C> for str {
type Src = str;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(C::LengthEncoding::write_bytes_needed(src.len())? + src.len())
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
C::LengthEncoding::write(writer.by_ref(), src.len())?;
writer.write(src.as_bytes())?;
Ok(())
}
}
#[cfg(feature = "alloc")]
unsafe impl<C: Config> SchemaWrite<C> for String {
type Src = String;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<str as SchemaWrite<C>>::size_of(src)
}
#[inline]
fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
C::LengthEncoding::prealloc_check::<u8>(src.len())?;
<str as SchemaWrite<C>>::write(writer, src)
}
}
unsafe impl<'de, C: Config> SchemaRead<'de, C> for &'de str {
type Dst = &'de str;
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = C::LengthEncoding::read(reader.by_ref())?;
<&'de str as SchemaReadContext<C, _>>::read_with_context(context::Len(len), reader, dst)
}
}
unsafe impl<'de, C: ConfigCore> SchemaReadContext<'de, C, context::Len> for &'de str {
type Dst = &'de str;
#[inline]
fn read_with_context(
context::Len(len): context::Len,
mut reader: impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let bytes = reader.take_borrowed(len)?;
match core::str::from_utf8(bytes) {
Ok(s) => {
dst.write(s);
Ok(())
}
Err(e) => Err(invalid_utf8_encoding(e)),
}
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, C: Config> SchemaRead<'de, C> for String {
type Dst = String;
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = C::LengthEncoding::read_prealloc_check::<u8>(reader.by_ref())?;
<String as SchemaReadContext<C, _>>::read_with_context(context::Len(len), reader, dst)
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, C: Config> SchemaReadContext<'de, C, context::Len> for String {
type Dst = String;
#[inline]
fn read_with_context(
ctx: context::Len,
reader: impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let bytes = <Vec<u8> as SchemaReadContext<C, _>>::get_with_context(ctx, reader)?;
match String::from_utf8(bytes) {
Ok(s) => {
dst.write(s);
Ok(())
}
Err(e) => Err(invalid_utf8_encoding(e.utf8_error())),
}
}
}
macro_rules! impl_seq_kv {
($feature: literal,
$target: ident<$key: ident : $($constraint:path)|*, $value: ident $(, $state:ident : $($state_constraint:path)|* )?>,
$with_capacity: expr) => {
#[cfg(feature = $feature)]
unsafe impl<C: $crate::config::Config, $key, $value $(, $state)?> $crate::schema::SchemaWrite<C> for $target<$key, $value $(, $state)?>
where
$key: $crate::schema::SchemaWrite<C>,
$key::Src: Sized,
$value: $crate::schema::SchemaWrite<C>,
$value::Src: Sized
$($(, $state: $state_constraint+)*)?
{
type Src = $target<$key::Src, $value::Src $(, $state)?>;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> $crate::error::WriteResult<usize> {
if let ($crate::TypeMeta::Static { size: key_size, .. }, $crate::TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
return Ok(C::LengthEncoding::write_bytes_needed(src.len())? + (key_size + value_size) * src.len());
}
Ok(C::LengthEncoding::write_bytes_needed(src.len())? +
src
.iter()
.try_fold(
0usize,
|acc, (k, v)|
Ok::<_, $crate::error::WriteError>(
acc
+ $key::size_of(k)?
+ $value::size_of(v)?
)
)?
)
}
#[inline]
fn write(mut writer: impl $crate::io::Writer, src: &Self::Src) -> $crate::error::WriteResult<()> {
if let ($crate::TypeMeta::Static { size: key_size, .. }, $crate::TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
let len = src.len();
#[allow(clippy::arithmetic_side_effects)]
let needed = C::LengthEncoding::write_bytes_needed_prealloc_check::<($key, $value)>(len)? + (key_size + value_size) * len;
let mut writer = unsafe { writer.as_trusted_for(needed) }?;
C::LengthEncoding::write(writer.by_ref(), len)?;
for (k, v) in src.iter() {
$key::write(writer.by_ref(), k)?;
$value::write(writer.by_ref(), v)?;
}
writer.finish()?;
return Ok(());
}
C::LengthEncoding::write(writer.by_ref(), src.len())?;
for (k, v) in src.iter() {
$key::write(writer.by_ref(), k)?;
$value::write(writer.by_ref(), v)?;
}
Ok(())
}
}
#[cfg(feature = $feature)]
unsafe impl<'de, C: $crate::config::Config, $key, $value $(, $state)?> $crate::schema::SchemaRead<'de, C> for $target<$key, $value $(, $state)?>
where
$key: $crate::schema::SchemaRead<'de, C>,
$value: $crate::schema::SchemaRead<'de, C>
$(,$key::Dst: $constraint+)*
$($(, $state: $state_constraint+)* )?
{
type Dst = $target<$key::Dst, $value::Dst $(, $state)?>;
#[inline]
fn read(mut reader: impl $crate::io::Reader<'de>, dst: &mut core::mem::MaybeUninit<Self::Dst>) -> $crate::error::ReadResult<()> {
let len = C::LengthEncoding::read_prealloc_check::<($key::Dst, $value::Dst)>(reader.by_ref())?;
let map = if let ($crate::TypeMeta::Static { size: key_size, .. }, $crate::TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
#[allow(clippy::arithmetic_side_effects)]
let mut reader = unsafe { reader.as_trusted_for((key_size + value_size) * len) }?;
let mut map = $with_capacity(len $(, $state::default())?);
for _ in 0..len {
let k = $key::get(reader.by_ref())?;
let v = $value::get(reader.by_ref())?;
map.insert(k, v);
}
map
} else {
let mut map = $with_capacity(len $(, $state::default())?);
for _ in 0..len {
let k = $key::get(reader.by_ref())?;
let v = $value::get(reader.by_ref())?;
map.insert(k, v);
}
map
};
dst.write(map);
Ok(())
}
}
};
}
pub(crate) use impl_seq_kv;
macro_rules! impl_seq_v {
($feature: literal,
$target: ident <$key: ident : $($constraint:path)|* $(, $state:ident : $($state_constraint:path)|*)?>,
$with_capacity: expr, $insert: ident) => {
#[cfg(feature = $feature)]
unsafe impl<C: $crate::config::Config, $key: $crate::schema::SchemaWrite<C> $(, $state)?> $crate::schema::SchemaWrite<C> for $target<$key $(, $state)?>
where
$key::Src: Sized
$($(, $state: $state_constraint+)* )?
{
type Src = $target<$key::Src $(, $state)?>;
#[inline]
fn size_of(src: &Self::Src) -> $crate::error::WriteResult<usize> {
$crate::schema::size_of_elem_iter::<$key, C::LengthEncoding, C>(src.iter())
}
#[inline]
fn write(writer: impl $crate::io::Writer, src: &Self::Src) -> $crate::error::WriteResult<()> {
$crate::schema::write_elem_iter_prealloc_check::<$key, C::LengthEncoding, C>(writer, src.iter())
}
}
#[cfg(feature = $feature)]
unsafe impl<'de, C: $crate::config::Config, $key $(, $state)?> $crate::schema::SchemaRead<'de, C> for $target<$key $(, $state)?>
where
$key: $crate::schema::SchemaRead<'de, C>
$(,$key::Dst: $constraint+)*
$($(, $state: $state_constraint+)* )?
{
type Dst = $target<$key::Dst $(, $state)?>;
#[inline]
fn read(mut reader: impl $crate::io::Reader<'de>, dst: &mut core::mem::MaybeUninit<Self::Dst>) -> $crate::error::ReadResult<()> {
let len = C::LengthEncoding::read_prealloc_check::<$key::Dst>(reader.by_ref())?;
let map = match $key::TYPE_META {
$crate::TypeMeta::Static { size, .. } => {
#[allow(clippy::arithmetic_side_effects)]
let mut reader = unsafe { reader.as_trusted_for(size * len) }?;
let mut set = $with_capacity(len $(, $state::default())?);
for _ in 0..len {
set.$insert($key::get(reader.by_ref())?);
}
set
}
$crate::TypeMeta::Dynamic => {
let mut set = $with_capacity(len $(, $state::default())?);
for _ in 0..len {
set.$insert($key::get(reader.by_ref())?);
}
set
}
};
dst.write(map);
Ok(())
}
}
};
}
pub(crate) use impl_seq_v;
impl_seq_kv! { "alloc", BTreeMap<K: Ord, V>, |_| BTreeMap::new() }
impl_seq_kv! { "std", HashMap<K: Hash | Eq, V, S: BuildHasher | Default>, HashMap::with_capacity_and_hasher }
impl_seq_v! { "alloc", BTreeSet<K: Ord>, |_| BTreeSet::new(), insert }
impl_seq_v! { "std", HashSet<K: Hash | Eq, S: BuildHasher | Default>, HashSet::with_capacity_and_hasher, insert }
impl_seq_v! { "alloc", LinkedList<K:>, |_| LinkedList::new(), push_back }
#[cfg(feature = "alloc")]
unsafe impl<T, C: Config> SchemaWrite<C> for BinaryHeap<T>
where
T: SchemaWrite<C>,
T::Src: Sized,
{
type Src = BinaryHeap<T::Src>;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<containers::BinaryHeap<T, C::LengthEncoding>>::size_of(src)
}
#[inline]
fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
<containers::BinaryHeap<T, C::LengthEncoding>>::write(writer, src)
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for BinaryHeap<T>
where
T: SchemaRead<'de, C>,
T::Dst: Ord,
{
type Dst = BinaryHeap<T::Dst>;
#[inline]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
<containers::BinaryHeap<T, C::LengthEncoding>>::read(reader, dst)
}
}
mod zero_copy {
use {
super::*,
core::slice::{from_raw_parts, from_raw_parts_mut},
};
#[inline(always)]
fn cast_ensure_aligned<C: ConfigCore, T, U>(ptr: *const T) -> ReadResult<*const U> {
let ptr = ptr.cast::<U>();
if !C::ZERO_COPY_ALIGN_CHECK {
return Ok(ptr);
}
if align_of::<U>() > 1 && !ptr.is_aligned() {
return Err(unaligned_pointer_read());
}
Ok(ptr)
}
#[inline(always)]
fn cast_ensure_aligned_mut<C: ConfigCore, T, U>(ptr: *mut T) -> ReadResult<*mut U> {
let ptr = ptr.cast::<U>();
if !C::ZERO_COPY_ALIGN_CHECK {
return Ok(ptr);
}
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<C: ConfigCore, T>(bytes: &[u8]) -> ReadResult<&T> {
debug_assert_eq!(bytes.len(), size_of::<T>());
let ptr = cast_ensure_aligned::<C, u8, T>(bytes.as_ptr())?;
let val = unsafe { &*ptr };
Ok(val)
}
#[inline(always)]
pub(super) unsafe fn cast_slice_to_t_mut<C: ConfigCore, T>(
bytes: &mut [u8],
) -> ReadResult<&mut T> {
debug_assert_eq!(bytes.len(), size_of::<T>());
let ptr = cast_ensure_aligned_mut::<C, u8, T>(bytes.as_mut_ptr())?;
let val = unsafe { &mut *ptr };
Ok(val)
}
#[inline(always)]
pub(super) unsafe fn cast_slice_to_slice_t<C: ConfigCore, T>(
bytes: &[u8],
len: usize,
) -> ReadResult<&[T]> {
debug_assert_eq!(Some(bytes.len()), len.checked_mul(size_of::<T>()));
let ptr = cast_ensure_aligned::<C, 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<C: ConfigCore, 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::<C, 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, C: ConfigCore>() -> TypeMeta
where
T: SchemaRead<'de, C> + ZeroCopy<C>,
{
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, C: ConfigCore>() -> TypeMeta
where
T: SchemaRead<'de, C> + ZeroCopy<C>,
{
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, C: Config>(
reader: impl Reader<'de>,
size: usize,
) -> ReadResult<(usize, usize)> {
let len = C::LengthEncoding::read(reader)?;
let Some(total_size) = len.checked_mul(size) else {
return Err(read_length_encoding_overflow("usize::MAX"));
};
Ok((len, total_size))
}
}
unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for &'de T
where
T: SchemaRead<'de, C> + ZeroCopy<C>,
{
type Dst = &'de T::Dst;
const TYPE_META: TypeMeta = zero_copy::type_meta_t::<T, C>();
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let size = T::TYPE_META.size_assert_zero_copy();
let bytes = reader.take_borrowed(size)?;
let val = unsafe { zero_copy::cast_slice_to_t::<C, T::Dst>(bytes)? };
dst.write(val);
Ok(())
}
}
unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for &'de mut T
where
T: SchemaRead<'de, C> + ZeroCopy<C>,
{
type Dst = &'de mut T::Dst;
const TYPE_META: TypeMeta = zero_copy::type_meta_t::<T, C>();
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let size = T::TYPE_META.size_assert_zero_copy();
let bytes = reader.take_borrowed_mut(size)?;
let val = unsafe { zero_copy::cast_slice_to_t_mut::<C, T::Dst>(bytes)? };
dst.write(val);
Ok(())
}
}
unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for &'de [T]
where
T: SchemaRead<'de, C> + ZeroCopy<C>,
{
type Dst = &'de [T::Dst];
const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T, C>();
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let len = C::LengthEncoding::read(reader.by_ref())?;
<&[T]>::read_with_context(context::Len(len), reader, dst)?;
Ok(())
}
}
unsafe impl<'de, T, C: ConfigCore> SchemaReadContext<'de, C, context::Len> for &'de [T]
where
T: SchemaRead<'de, C> + ZeroCopy<C>,
{
type Dst = &'de [T::Dst];
const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T, C>();
#[inline]
fn read_with_context(
context::Len(len): context::Len,
mut reader: impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let size = T::TYPE_META.size_assert_zero_copy();
let Some(total_size) = len.checked_mul(size) else {
return Err(read_length_encoding_overflow("usize::MAX"));
};
let bytes = reader.take_borrowed(total_size)?;
let slice = unsafe { zero_copy::cast_slice_to_slice_t::<C, T::Dst>(bytes, len)? };
dst.write(slice);
Ok(())
}
}
unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for &'de mut [T]
where
T: SchemaRead<'de, C> + ZeroCopy<C>,
{
type Dst = &'de mut [T::Dst];
const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T, C>();
fn read(mut reader: 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::<C>(reader.by_ref(), size)?;
let bytes = reader.take_borrowed_mut(total_size)?;
let slice = unsafe { zero_copy::cast_slice_to_slice_t_mut::<C, T::Dst>(bytes, len)? };
dst.write(slice);
Ok(())
}
}
unsafe impl<C: ConfigCore> SchemaWrite<C> for Duration {
type Src = Duration;
const TYPE_META: TypeMeta = match (
<u64 as SchemaWrite<C>>::TYPE_META,
<u32 as SchemaWrite<C>>::TYPE_META,
) {
(TypeMeta::Static { size: u64_size, .. }, TypeMeta::Static { size: u32_size, .. }) => {
TypeMeta::Static {
size: u64_size + u32_size,
zero_copy: false,
}
}
_ => TypeMeta::Dynamic,
};
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
match <Self as SchemaWrite<C>>::TYPE_META {
TypeMeta::Static { size, .. } => Ok(size),
TypeMeta::Dynamic => {
let secs = <u64 as SchemaWrite<C>>::size_of(&src.as_secs())?;
let nanos = <u32 as SchemaWrite<C>>::size_of(&src.subsec_nanos())?;
Ok(secs + nanos)
}
}
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
<u64 as SchemaWrite<C>>::write(writer.by_ref(), &src.as_secs())?;
<u32 as SchemaWrite<C>>::write(writer, &src.subsec_nanos())?;
Ok(())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for Duration {
type Dst = Duration;
const TYPE_META: TypeMeta = <Duration as SchemaWrite<C>>::TYPE_META;
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let secs = <u64 as SchemaRead<'de, C>>::get(reader.by_ref())?;
let nanos = <u32 as SchemaRead<'de, C>>::get(reader)?;
if secs.checked_add(u64::from(nanos) / 1_000_000_000).is_none() {
return Err(invalid_value("Duration overflow"));
}
dst.write(Duration::new(secs, nanos));
Ok(())
}
}
#[cfg(feature = "std")]
unsafe impl<C: ConfigCore> SchemaWrite<C> for SystemTime {
type Src = SystemTime;
const TYPE_META: TypeMeta = <Duration as SchemaWrite<C>>::TYPE_META;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
match <Self as SchemaWrite<C>>::TYPE_META {
TypeMeta::Static { size, .. } => Ok(size),
TypeMeta::Dynamic => {
let duration = src.duration_since(UNIX_EPOCH).map_err(|_| {
crate::error::WriteError::Custom("SystemTime before UNIX_EPOCH")
})?;
<Duration as SchemaWrite<C>>::size_of(&duration)
}
}
}
#[inline]
fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
let duration = src
.duration_since(UNIX_EPOCH)
.map_err(|_| crate::error::WriteError::Custom("SystemTime before UNIX_EPOCH"))?;
<Duration as SchemaWrite<C>>::write(writer, &duration)?;
Ok(())
}
}
#[cfg(feature = "std")]
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for SystemTime {
type Dst = SystemTime;
const TYPE_META: TypeMeta = <Duration as SchemaRead<'de, C>>::TYPE_META;
#[inline]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let duration = <Duration as SchemaRead<'de, C>>::get(reader)?;
let system_time = UNIX_EPOCH
.checked_add(duration)
.ok_or_else(|| invalid_value("SystemTime overflow"))?;
dst.write(system_time);
Ok(())
}
}
unsafe impl<C: ConfigCore> SchemaWrite<C> for Ipv4Addr {
type Src = Ipv4Addr;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 4,
zero_copy: false,
};
#[inline]
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(4)
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
writer.write(&src.octets())?;
Ok(())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for Ipv4Addr {
type Dst = Ipv4Addr;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 4,
zero_copy: false,
};
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let bytes = reader.take_array::<4>()?;
dst.write(Ipv4Addr::from(bytes));
Ok(())
}
}
unsafe impl<C: ConfigCore> SchemaWrite<C> for Ipv6Addr {
type Src = Ipv6Addr;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 16,
zero_copy: false,
};
#[inline]
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(16)
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
writer.write(&src.octets())?;
Ok(())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for Ipv6Addr {
type Dst = Ipv6Addr;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 16,
zero_copy: false,
};
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let bytes = reader.take_array::<16>()?;
dst.write(Ipv6Addr::from(bytes));
Ok(())
}
}
unsafe impl<C: Config> SchemaWrite<C> for IpAddr {
type Src = IpAddr;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(match src {
IpAddr::V4(_) => C::TagEncoding::size_of_from_u32(0)? + 4,
IpAddr::V6(_) => C::TagEncoding::size_of_from_u32(1)? + 16,
})
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
match src {
IpAddr::V4(addr) => {
C::TagEncoding::write_from_u32(writer.by_ref(), 0)?;
<Ipv4Addr as SchemaWrite<C>>::write(writer, addr)
}
IpAddr::V6(addr) => {
C::TagEncoding::write_from_u32(writer.by_ref(), 1)?;
<Ipv6Addr as SchemaWrite<C>>::write(writer, addr)
}
}
}
}
unsafe impl<'de, C: Config> SchemaRead<'de, C> for IpAddr {
type Dst = IpAddr;
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let tag = C::TagEncoding::try_into_u32(C::TagEncoding::get(reader.by_ref())?)?;
match tag {
0 => {
let addr = <Ipv4Addr as SchemaRead<'de, C>>::get(reader)?;
dst.write(IpAddr::V4(addr));
Ok(())
}
1 => {
let addr = <Ipv6Addr as SchemaRead<'de, C>>::get(reader)?;
dst.write(IpAddr::V6(addr));
Ok(())
}
_ => Err(invalid_tag_encoding(tag as usize)),
}
}
}
unsafe impl<C: ConfigCore> SchemaWrite<C> for SocketAddrV4 {
type Src = Self;
const TYPE_META: TypeMeta = TypeMeta::join_types([
<Ipv4Addr as SchemaWrite<C>>::TYPE_META,
<u16 as SchemaWrite<C>>::TYPE_META,
]);
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(4 + <u16 as SchemaWrite<C>>::size_of(&src.port())?)
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
<Ipv4Addr as SchemaWrite<C>>::write(writer.by_ref(), src.ip())?;
<u16 as SchemaWrite<C>>::write(writer, &src.port())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for SocketAddrV4 {
type Dst = Self;
const TYPE_META: TypeMeta = TypeMeta::join_types([
<Ipv4Addr as SchemaRead<C>>::TYPE_META,
<u16 as SchemaRead<C>>::TYPE_META,
]);
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let ip = <Ipv4Addr as SchemaRead<'de, C>>::get(reader.by_ref())?;
let port = <u16 as SchemaRead<'de, C>>::get(reader)?;
dst.write(Self::Dst::new(ip, port));
Ok(())
}
}
unsafe impl<C: ConfigCore> SchemaWrite<C> for SocketAddrV6 {
type Src = Self;
const TYPE_META: TypeMeta = TypeMeta::join_types([
<Ipv6Addr as SchemaWrite<C>>::TYPE_META,
<u16 as SchemaWrite<C>>::TYPE_META,
]);
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(16 + <u16 as SchemaWrite<C>>::size_of(&src.port())?)
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
<Ipv6Addr as SchemaWrite<C>>::write(writer.by_ref(), src.ip())?;
<u16 as SchemaWrite<C>>::write(writer, &src.port())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for SocketAddrV6 {
type Dst = Self;
const TYPE_META: TypeMeta = TypeMeta::join_types([
<Ipv6Addr as SchemaRead<C>>::TYPE_META,
<u16 as SchemaRead<C>>::TYPE_META,
]);
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let ip = <Ipv6Addr as SchemaRead<'de, C>>::get(reader.by_ref())?;
let port = <u16 as SchemaRead<'de, C>>::get(reader)?;
dst.write(SocketAddrV6::new(ip, port, 0, 0));
Ok(())
}
}
unsafe impl<C: Config> SchemaWrite<C> for SocketAddr {
type Src = Self;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(match src {
Self::V4(v4) => {
C::TagEncoding::size_of_from_u32(0)?
+ <SocketAddrV4 as SchemaWrite<C>>::size_of(v4)?
}
Self::V6(v6) => {
C::TagEncoding::size_of_from_u32(1)?
+ <SocketAddrV6 as SchemaWrite<C>>::size_of(v6)?
}
})
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
match src {
Self::V4(addr) => {
C::TagEncoding::write_from_u32(writer.by_ref(), 0)?;
<SocketAddrV4 as SchemaWrite<C>>::write(writer, addr)
}
Self::V6(addr) => {
C::TagEncoding::write_from_u32(writer.by_ref(), 1)?;
<SocketAddrV6 as SchemaWrite<C>>::write(writer, addr)
}
}
}
}
unsafe impl<'de, C: Config> SchemaRead<'de, C> for SocketAddr {
type Dst = Self;
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let tag = C::TagEncoding::try_into_u32(C::TagEncoding::get(reader.by_ref())?)?;
match tag {
0 => {
let addr = <SocketAddrV4 as SchemaRead<'de, C>>::get(reader)?;
dst.write(Self::V4(addr));
Ok(())
}
1 => {
let addr = <SocketAddrV6 as SchemaRead<'de, C>>::get(reader)?;
dst.write(Self::V6(addr));
Ok(())
}
_ => Err(invalid_tag_encoding(tag as usize)),
}
}
}
macro_rules! impl_nonzero {
($($nonzero_ty:ty => $primitive_ty:ty),* $(,)?) => {
$(
unsafe impl<C: ConfigCore> SchemaWrite<C> for $nonzero_ty {
type Src = $nonzero_ty;
const TYPE_META: TypeMeta = <$primitive_ty as SchemaWrite<C>>::TYPE_META;
#[inline(always)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
<$primitive_ty as SchemaWrite<C>>::size_of(&src.get())
}
#[inline(always)]
fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
<$primitive_ty as SchemaWrite<C>>::write(writer, &src.get())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $nonzero_ty {
type Dst = $nonzero_ty;
const TYPE_META: TypeMeta = const {
match <$primitive_ty as SchemaRead<'de, C>>::TYPE_META {
TypeMeta::Static { size, .. } => TypeMeta::Static {
size,
zero_copy: false,
},
TypeMeta::Dynamic => TypeMeta::Dynamic,
}
};
#[inline(always)]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let val = <$primitive_ty as SchemaRead<'de, C>>::get(reader)?;
let nonzero = <$nonzero_ty>::new(val)
.ok_or_else(|| invalid_value(concat!(
"NonZero value cannot be zero for type ",
stringify!($nonzero_ty)
)))?;
dst.write(nonzero);
Ok(())
}
}
)*
};
}
impl_nonzero!(
NonZeroU8 => u8,
NonZeroU16 => u16,
NonZeroU32 => u32,
NonZeroU64 => u64,
NonZeroU128 => u128,
NonZeroUsize => usize,
NonZeroI8 => i8,
NonZeroI16 => i16,
NonZeroI32 => i32,
NonZeroI64 => i64,
NonZeroI128 => i128,
NonZeroIsize => isize,
);
unsafe impl<C: Config, T> SchemaWrite<C> for Bound<T>
where
T: SchemaWrite<C>,
T::Src: Sized,
{
type Src = Bound<T::Src>;
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
match src {
Bound::Unbounded => C::TagEncoding::size_of_from_u32(0),
Bound::Included(value) => Ok(C::TagEncoding::size_of_from_u32(1)? + T::size_of(value)?),
Bound::Excluded(value) => Ok(C::TagEncoding::size_of_from_u32(2)? + T::size_of(value)?),
}
}
#[inline]
fn write(mut writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
match value {
Bound::Unbounded => C::TagEncoding::write_from_u32(writer.by_ref(), 0),
Bound::Included(value) => {
C::TagEncoding::write_from_u32(writer.by_ref(), 1)?;
T::write(writer, value)
}
Bound::Excluded(value) => {
C::TagEncoding::write_from_u32(writer.by_ref(), 2)?;
T::write(writer, value)
}
}
}
}
unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Bound<T>
where
T: SchemaRead<'de, C>,
{
type Dst = Bound<T::Dst>;
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let disc = C::TagEncoding::try_into_u32(C::TagEncoding::get(reader.by_ref())?)?;
match disc {
0 => dst.write(Bound::Unbounded),
1 => dst.write(Bound::Included(T::get(reader.by_ref())?)),
2 => dst.write(Bound::Excluded(T::get(reader.by_ref())?)),
_ => return Err(invalid_tag_encoding(disc as usize)),
};
Ok(())
}
}
unsafe impl<Idx, C: Config> SchemaWrite<C> for Range<Idx>
where
Idx: SchemaWrite<C>,
Idx::Src: Sized,
{
type Src = Range<Idx::Src>;
const TYPE_META: TypeMeta = const {
match Idx::TYPE_META {
TypeMeta::Static { size: idx_size, .. } => TypeMeta::Static {
size: idx_size + idx_size,
zero_copy: false,
},
TypeMeta::Dynamic => TypeMeta::Dynamic,
}
};
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(Idx::size_of(&src.start)? + Idx::size_of(&src.end)?)
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
match Self::TYPE_META {
TypeMeta::Static { size, .. } => {
let mut writer = unsafe { writer.as_trusted_for(size) }?;
Idx::write(writer.by_ref(), &src.start)?;
Idx::write(writer.by_ref(), &src.end)?;
writer.finish()?;
}
TypeMeta::Dynamic => {
Idx::write(writer.by_ref(), &src.start)?;
Idx::write(writer.by_ref(), &src.end)?;
}
}
Ok(())
}
}
unsafe impl<'de, Idx, C: ConfigCore> SchemaRead<'de, C> for Range<Idx>
where
Idx: SchemaRead<'de, C>,
{
type Dst = Range<Idx::Dst>;
const TYPE_META: TypeMeta = const {
match Idx::TYPE_META {
TypeMeta::Static { size: idx_size, .. } => TypeMeta::Static {
size: idx_size + idx_size,
zero_copy: false,
},
TypeMeta::Dynamic => TypeMeta::Dynamic,
}
};
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
match Self::TYPE_META {
TypeMeta::Static { size, .. } => {
let mut reader = unsafe { reader.as_trusted_for(size) }?;
let start = Idx::get(reader.by_ref())?;
let end = Idx::get(reader.by_ref())?;
dst.write(Range { start, end });
}
TypeMeta::Dynamic => {
let start = Idx::get(reader.by_ref())?;
let end = Idx::get(reader.by_ref())?;
dst.write(Range { start, end });
}
};
Ok(())
}
}
unsafe impl<Idx, C: ConfigCore> SchemaWrite<C> for RangeInclusive<Idx>
where
Idx: SchemaWrite<C>,
Idx::Src: Sized,
{
type Src = RangeInclusive<Idx::Src>;
const TYPE_META: TypeMeta = const {
match Idx::TYPE_META {
TypeMeta::Static { size: idx_size, .. } => TypeMeta::Static {
size: idx_size + idx_size,
zero_copy: false,
},
TypeMeta::Dynamic => TypeMeta::Dynamic,
}
};
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
if let TypeMeta::Static { size, .. } = Self::TYPE_META {
return Ok(size);
}
Ok(Idx::size_of(src.start())? + Idx::size_of(src.end())?)
}
#[inline]
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
match Self::TYPE_META {
TypeMeta::Static { size, .. } => {
let mut writer = unsafe { writer.as_trusted_for(size) }?;
Idx::write(writer.by_ref(), src.start())?;
Idx::write(writer.by_ref(), src.end())?;
writer.finish()?;
}
TypeMeta::Dynamic => {
Idx::write(writer.by_ref(), src.start())?;
Idx::write(writer.by_ref(), src.end())?;
}
}
Ok(())
}
}
unsafe impl<'de, Idx, C: ConfigCore> SchemaRead<'de, C> for RangeInclusive<Idx>
where
Idx: SchemaRead<'de, C>,
{
type Dst = RangeInclusive<Idx::Dst>;
const TYPE_META: TypeMeta = const {
match Idx::TYPE_META {
TypeMeta::Static { size: idx_size, .. } => TypeMeta::Static {
size: idx_size + idx_size,
zero_copy: false,
},
TypeMeta::Dynamic => TypeMeta::Dynamic,
}
};
#[inline]
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
match Self::TYPE_META {
TypeMeta::Static { size, .. } => {
let mut reader = unsafe { reader.as_trusted_for(size) }?;
let start = Idx::get(reader.by_ref())?;
let end = Idx::get(reader.by_ref())?;
dst.write(RangeInclusive::new(start, end));
}
TypeMeta::Dynamic => {
let start = Idx::get(reader.by_ref())?;
let end = Idx::get(reader.by_ref())?;
dst.write(RangeInclusive::new(start, end));
}
};
Ok(())
}
}
#[cfg(feature = "alloc")]
unsafe impl<T: ?Sized, C: ConfigCore> SchemaWrite<C> for Cow<'_, T>
where
T: ToOwned,
T: SchemaWrite<C, Src = T>,
{
type Src = Self;
#[inline]
fn size_of(src: &Self::Src) -> WriteResult<usize> {
T::size_of(src.as_ref())
}
#[inline]
fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
T::write(writer, src.as_ref())
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, T: ?Sized, C: ConfigCore> SchemaRead<'de, C> for Cow<'de, T>
where
T: ToOwned,
&'de T: SchemaRead<'de, C, Dst = &'de T>,
T::Owned: SchemaRead<'de, C, Dst = T::Owned>,
{
type Dst = Self;
#[inline]
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let cow = if reader.supports_borrow(BorrowKind::Backing) {
Cow::Borrowed(<&T as SchemaRead<C>>::get(reader)?)
} else {
Cow::Owned(<T::Owned as SchemaRead<C>>::get(reader)?)
};
dst.write(cow);
Ok(())
}
}
#[cfg(feature = "alloc")]
unsafe impl<'de, T, C: ConfigCore> SchemaReadContext<'de, C, context::Len> for Cow<'de, [T]>
where
[T]: ToOwned,
&'de [T]: SchemaReadContext<'de, C, context::Len, Dst = &'de [T]>,
<[T] as ToOwned>::Owned: SchemaReadContext<'de, C, context::Len, Dst = <[T] as ToOwned>::Owned>,
{
type Dst = Self;
#[inline]
fn read_with_context(
ctx: context::Len,
reader: impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let cow = if reader.supports_borrow(BorrowKind::Backing) {
Cow::Borrowed(<&[T]>::get_with_context(ctx, reader)?)
} else {
Cow::Owned(<<[T] as ToOwned>::Owned>::get_with_context(ctx, reader)?)
};
dst.write(cow);
Ok(())
}
}