use {
crate::{
config::{self, ConfigCore, DefaultConfig},
error::{ReadResult, WriteResult},
io::*,
len::SeqLen,
},
core::{borrow::Borrow, mem::MaybeUninit},
};
pub mod containers;
pub mod context;
mod external;
mod impls;
pub mod int_encoding;
pub mod tag_encoding;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TypeMeta {
Static {
size: usize,
zero_copy: bool,
},
Dynamic,
}
impl TypeMeta {
#[inline(always)]
pub(crate) const fn size_assert_zero_copy(self) -> usize {
match self {
TypeMeta::Static {
size,
zero_copy: true,
} => size,
_ => panic!("Type is not zero-copy"),
}
}
#[cfg(all(test, feature = "std", feature = "derive"))]
pub(crate) const fn size_assert_static(self) -> usize {
match self {
TypeMeta::Static { size, zero_copy: _ } => size,
_ => panic!("Type is not static"),
}
}
pub const fn keep_zero_copy(self, keep_zero_copy: bool) -> Self {
match self {
Self::Static { size, zero_copy } => TypeMeta::Static {
size,
zero_copy: zero_copy && keep_zero_copy,
},
Self::Dynamic => Self::Dynamic,
}
}
#[expect(clippy::arithmetic_side_effects)]
pub const fn join_types<const N: usize>(types: [Self; N]) -> Self {
let mut acc_size = 0;
let mut all_zero_copy = true;
let mut i = 0;
while i < N {
match types[i] {
Self::Dynamic => return Self::Dynamic,
Self::Static { size, zero_copy } => {
acc_size += size;
all_zero_copy &= zero_copy;
}
}
i += 1;
}
Self::Static {
size: acc_size,
zero_copy: all_zero_copy,
}
}
}
pub unsafe trait SchemaWrite<C: ConfigCore> {
type Src: ?Sized;
const TYPE_META: TypeMeta = TypeMeta::Dynamic;
#[cfg(test)]
#[allow(unused_variables)]
fn type_meta(config: C) -> TypeMeta {
Self::TYPE_META
}
fn size_of(src: &Self::Src) -> WriteResult<usize>;
fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()>;
}
pub unsafe trait SchemaRead<'de, C: ConfigCore> {
type Dst;
const TYPE_META: TypeMeta = TypeMeta::Dynamic;
#[cfg(test)]
#[allow(unused_variables)]
fn type_meta(config: C) -> TypeMeta {
Self::TYPE_META
}
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()>;
#[inline(always)]
fn get(reader: impl Reader<'de>) -> ReadResult<Self::Dst> {
let mut value = MaybeUninit::uninit();
Self::read(reader, &mut value)?;
Ok(unsafe { value.assume_init() })
}
}
pub unsafe trait SchemaReadContext<'de, C: ConfigCore, Ctx> {
type Dst;
const TYPE_META: TypeMeta = TypeMeta::Dynamic;
fn read_with_context(
ctx: Ctx,
reader: impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()>;
#[inline(always)]
fn get_with_context(ctx: Ctx, reader: impl Reader<'de>) -> ReadResult<Self::Dst> {
let mut value = MaybeUninit::uninit();
Self::read_with_context(ctx, reader, &mut value)?;
Ok(unsafe { value.assume_init() })
}
}
pub unsafe trait ZeroCopy: config::ZeroCopy<DefaultConfig> {
#[inline(always)]
fn from_bytes<'de>(bytes: &'de [u8]) -> ReadResult<&'de Self>
where
Self: SchemaRead<'de, DefaultConfig, Dst = Self> + Sized,
{
<&Self as SchemaRead<'de, DefaultConfig>>::get(bytes)
}
#[inline(always)]
fn from_bytes_mut<'de>(bytes: &'de mut [u8]) -> ReadResult<&'de mut Self>
where
Self: SchemaRead<'de, DefaultConfig, Dst = Self> + Sized,
{
<&mut Self as SchemaRead<'de, DefaultConfig>>::get(bytes)
}
}
unsafe impl<T> ZeroCopy for T where T: config::ZeroCopy<DefaultConfig> {}
pub trait SchemaReadOwned<C: ConfigCore>: for<'de> SchemaRead<'de, C> {}
impl<T, C: ConfigCore> SchemaReadOwned<C> for T where T: for<'de> SchemaRead<'de, C> {}
#[inline(always)]
#[allow(clippy::arithmetic_side_effects)]
fn size_of_elem_iter<T, Len, C>(
value: impl ExactSizeIterator<Item: Borrow<T::Src>>,
) -> WriteResult<usize>
where
C: ConfigCore,
Len: SeqLen<C>,
T: SchemaWrite<C>,
{
if let TypeMeta::Static { size, .. } = T::TYPE_META {
return Ok(Len::write_bytes_needed(value.len())? + size * value.len());
}
Ok(Len::write_bytes_needed(value.len())?
+ (value
.map(|x| T::size_of(x.borrow()))
.try_fold(0usize, |acc, x| x.map(|x| acc + x))?))
}
#[inline(always)]
#[allow(clippy::arithmetic_side_effects)]
fn size_of_elem_slice<T, Len, C>(value: &[T::Src]) -> WriteResult<usize>
where
C: ConfigCore,
Len: SeqLen<C>,
T: SchemaWrite<C>,
T::Src: Sized,
{
size_of_elem_iter::<T, Len, C>(value.iter())
}
#[inline(always)]
fn write_elem_iter<T, Len, C>(
mut writer: impl Writer,
src: impl ExactSizeIterator<Item: Borrow<T::Src>>,
) -> WriteResult<()>
where
C: ConfigCore,
Len: SeqLen<C>,
T: SchemaWrite<C>,
{
if let TypeMeta::Static { size, .. } = T::TYPE_META {
#[allow(clippy::arithmetic_side_effects)]
let needed = Len::write_bytes_needed(src.len())? + size * src.len();
let mut writer = unsafe { writer.as_trusted_for(needed) }?;
Len::write(writer.by_ref(), src.len())?;
for item in src {
T::write(writer.by_ref(), item.borrow())?;
}
writer.finish()?;
return Ok(());
}
Len::write(writer.by_ref(), src.len())?;
for item in src {
T::write(writer.by_ref(), item.borrow())?;
}
Ok(())
}
#[inline(always)]
#[cfg(feature = "alloc")]
fn write_elem_iter_prealloc_check<'a, T, Len, C>(
writer: impl Writer,
src: impl ExactSizeIterator<Item = &'a T::Src>,
) -> WriteResult<()>
where
C: ConfigCore,
Len: SeqLen<C>,
T: SchemaWrite<C> + 'a,
{
Len::prealloc_check::<T>(src.len())?;
write_elem_iter::<T, Len, C>(writer, src)
}
#[inline(always)]
#[allow(clippy::arithmetic_side_effects)]
fn write_elem_slice<T, Len, C>(mut writer: impl Writer, src: &[T::Src]) -> WriteResult<()>
where
C: ConfigCore,
Len: SeqLen<C>,
T: SchemaWrite<C>,
T::Src: Sized,
{
if let TypeMeta::Static {
size,
zero_copy: true,
} = T::TYPE_META
{
let needed = Len::write_bytes_needed(src.len())? + src.len() * size;
let mut writer = unsafe { writer.as_trusted_for(needed) }?;
Len::write(writer.by_ref(), src.len())?;
unsafe { writer.write_slice_t(src)? };
writer.finish()?;
return Ok(());
}
write_elem_iter::<T, Len, C>(writer, src.iter())
}
#[inline(always)]
#[cfg(feature = "alloc")]
fn write_elem_slice_prealloc_check<T, Len, C>(
writer: impl Writer,
src: &[T::Src],
) -> WriteResult<()>
where
C: ConfigCore,
Len: SeqLen<C>,
T: SchemaWrite<C>,
T::Src: Sized,
{
Len::prealloc_check::<T>(src.len())?;
write_elem_slice::<T, Len, C>(writer, src)
}
#[cfg(all(test, feature = "std", feature = "derive"))]
mod tests {
#![allow(clippy::arithmetic_side_effects)]
use {
crate::{
Deserialize, ReadResult, SchemaRead, SchemaReadContext, SchemaWrite, Serialize,
TypeMeta, UninitBuilder, WriteResult, ZeroCopy,
config::{self, Config, ConfigCore, Configuration, DefaultConfig},
containers, context, deserialize, deserialize_exact, deserialize_mut,
error::{self, invalid_tag_encoding},
io::{Reader, Writer, test_util::NoBorrowReader},
len::{BincodeLen, FixIntLen},
pod_wrapper,
proptest_config::proptest_cfg,
serialize,
},
bincode::Options,
core::{marker::PhantomData, ptr},
proptest::prelude::*,
std::{
alloc::Layout,
borrow::Cow,
cell::Cell,
collections::{BinaryHeap, HashMap, HashSet, VecDeque},
hash::{BuildHasher, Hasher},
mem::MaybeUninit,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
num::{
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize,
NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
},
ops::{Bound, Deref, DerefMut, Range, RangeInclusive},
rc::Rc,
result::Result,
sync::Arc,
time::{Duration, SystemTime, UNIX_EPOCH},
},
};
#[cfg(target_endian = "little")]
#[derive(
serde::Serialize,
serde::Deserialize,
Debug,
PartialEq,
Eq,
Ord,
PartialOrd,
SchemaWrite,
SchemaRead,
proptest_derive::Arbitrary,
Hash,
Clone,
Copy,
)]
#[wincode(internal)]
#[repr(C)]
struct StructZeroCopy {
a: u128,
b: i128,
c: u64,
d: i64,
e: u32,
f: i32,
ar1: [u8; 8],
g: u16,
h: i16,
ar2: [u8; 12],
i: u8,
j: i8,
ar3: [u8; 14],
}
#[cfg(not(target_endian = "little"))]
#[derive(
serde::Serialize,
serde::Deserialize,
Debug,
PartialEq,
Eq,
Ord,
PartialOrd,
SchemaWrite,
SchemaRead,
proptest_derive::Arbitrary,
Hash,
Clone,
Copy,
)]
#[wincode(internal)]
#[repr(C)]
struct StructZeroCopy {
byte: u8,
ar: [u8; 32],
}
#[derive(
serde::Serialize,
serde::Deserialize,
Debug,
PartialEq,
Eq,
Ord,
PartialOrd,
SchemaWrite,
SchemaRead,
proptest_derive::Arbitrary,
Hash,
)]
#[wincode(internal)]
struct StructStatic {
a: u64,
b: bool,
e: [u8; 32],
}
#[derive(
serde::Serialize,
serde::Deserialize,
Debug,
PartialEq,
Eq,
Ord,
PartialOrd,
SchemaWrite,
SchemaRead,
proptest_derive::Arbitrary,
Hash,
)]
#[wincode(internal)]
struct StructNonStatic {
a: u64,
b: bool,
e: String,
}
#[test]
fn struct_zero_copy_derive_size() {
#[cfg(target_endian = "little")]
let size = size_of::<u128>()
+ size_of::<i128>()
+ size_of::<u64>()
+ size_of::<i64>()
+ size_of::<u32>()
+ size_of::<i32>()
+ size_of::<[u8; 8]>()
+ size_of::<u16>()
+ size_of::<i16>()
+ size_of::<[u8; 12]>()
+ size_of::<u8>()
+ size_of::<i8>()
+ size_of::<[u8; 14]>();
#[cfg(not(target_endian = "little"))]
let size = size_of::<u8>() + size_of::<[u8; 32]>();
let expected = TypeMeta::Static {
size,
zero_copy: true,
};
assert_eq!(
<StructZeroCopy as SchemaWrite<DefaultConfig>>::TYPE_META,
expected
);
assert_eq!(
<StructZeroCopy as SchemaRead<'_, DefaultConfig>>::TYPE_META,
expected
);
}
#[test]
fn struct_zero_copy_transparent_derive_size() {
#[derive(SchemaWrite, SchemaRead)]
#[wincode(internal)]
#[repr(transparent)]
struct Address([u8; 32]);
let expected = TypeMeta::Static {
size: size_of::<[u8; 32]>(),
zero_copy: true,
};
assert_eq!(<Address as SchemaWrite<DefaultConfig>>::TYPE_META, expected);
assert_eq!(
<Address as SchemaRead<'_, DefaultConfig>>::TYPE_META,
expected
);
}
#[test]
fn struct_static_derive_size() {
let expected = TypeMeta::Static {
size: size_of::<u64>() + size_of::<bool>() + size_of::<[u8; 32]>(),
zero_copy: false,
};
assert_eq!(
<StructStatic as SchemaWrite<DefaultConfig>>::TYPE_META,
expected
);
assert_eq!(
<StructStatic as SchemaRead<'_, DefaultConfig>>::TYPE_META,
expected
);
}
#[test]
fn struct_non_static_derive_size() {
let expected = TypeMeta::Dynamic;
assert_eq!(
<StructNonStatic as SchemaWrite<DefaultConfig>>::TYPE_META,
expected
);
assert_eq!(
<StructNonStatic as SchemaRead<'_, DefaultConfig>>::TYPE_META,
expected
);
}
thread_local! {
static TL_DROP_COUNT: Cell<isize> = const { Cell::new(0) };
}
fn get_tl_drop_count() -> isize {
TL_DROP_COUNT.with(|cell| cell.get())
}
fn tl_drop_count_inc() {
TL_DROP_COUNT.with(|cell| cell.set(cell.get() + 1));
}
fn tl_drop_count_dec() {
TL_DROP_COUNT.with(|cell| cell.set(cell.get() - 1));
}
fn tl_drop_count_reset() {
TL_DROP_COUNT.with(|cell| cell.set(0));
}
#[must_use]
#[derive(Debug)]
struct TLDropGuard;
impl TLDropGuard {
fn new() -> Self {
assert_eq!(
get_tl_drop_count(),
0,
"TL counter drifted from zero -- another test may have leaked"
);
Self
}
}
impl Drop for TLDropGuard {
#[track_caller]
fn drop(&mut self) {
let v = get_tl_drop_count();
if !std::thread::panicking() {
assert_eq!(
v, 0,
"TL counter drifted from zero -- this test might have leaked"
);
}
tl_drop_count_reset();
}
}
#[derive(Debug, PartialEq, Eq)]
struct DropCounted;
impl Arbitrary for DropCounted {
type Parameters = ();
type Strategy = Just<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
Just(Self::new())
}
}
impl DropCounted {
const TAG_BYTE: u8 = 0;
fn new() -> Self {
tl_drop_count_inc();
Self
}
}
impl Clone for DropCounted {
fn clone(&self) -> Self {
tl_drop_count_inc();
Self
}
}
impl Drop for DropCounted {
fn drop(&mut self) {
tl_drop_count_dec();
}
}
unsafe impl<C: Config> SchemaWrite<C> for DropCounted {
type Src = Self;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 1,
zero_copy: false,
};
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(1)
}
fn write(writer: impl Writer, _src: &Self::Src) -> WriteResult<()> {
<u8 as SchemaWrite<C>>::write(writer, &Self::TAG_BYTE)?;
Ok(())
}
}
unsafe impl<'de, C: Config> SchemaRead<'de, C> for DropCounted {
type Dst = Self;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 1,
zero_copy: false,
};
fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
reader.take_byte()?;
dst.write(DropCounted::new());
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, proptest_derive::Arbitrary)]
struct ErrorsOnRead;
impl ErrorsOnRead {
const TAG_BYTE: u8 = 1;
}
unsafe impl<C: Config> SchemaWrite<C> for ErrorsOnRead {
type Src = Self;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 1,
zero_copy: false,
};
fn size_of(_src: &Self::Src) -> WriteResult<usize> {
Ok(1)
}
fn write(writer: impl Writer, _src: &Self::Src) -> WriteResult<()> {
<u8 as SchemaWrite<C>>::write(writer, &Self::TAG_BYTE)
}
}
unsafe impl<'de, C: Config> SchemaRead<'de, C> for ErrorsOnRead {
type Dst = Self;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 1,
zero_copy: false,
};
fn read(mut reader: impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
reader.take_byte()?;
Err(error::ReadError::PointerSizedReadError)
}
}
#[derive(Debug, Clone, PartialEq, Eq, proptest_derive::Arbitrary)]
enum DropCountedMaybeError {
DropCounted(DropCounted),
ErrorsOnRead(ErrorsOnRead),
}
unsafe impl<C: Config> SchemaWrite<C> for DropCountedMaybeError {
type Src = Self;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 1,
zero_copy: false,
};
fn size_of(src: &Self::Src) -> WriteResult<usize> {
match src {
DropCountedMaybeError::DropCounted(v) => {
<DropCounted as SchemaWrite<C>>::size_of(v)
}
DropCountedMaybeError::ErrorsOnRead(v) => {
<ErrorsOnRead as SchemaWrite<C>>::size_of(v)
}
}
}
fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
match src {
DropCountedMaybeError::DropCounted(v) => {
<DropCounted as SchemaWrite<C>>::write(writer, v)
}
DropCountedMaybeError::ErrorsOnRead(v) => {
<ErrorsOnRead as SchemaWrite<C>>::write(writer, v)
}
}
}
}
unsafe impl<'de, C: Config> SchemaRead<'de, C> for DropCountedMaybeError {
type Dst = Self;
const TYPE_META: TypeMeta = TypeMeta::Static {
size: 1,
zero_copy: false,
};
fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let byte = <u8 as SchemaRead<'de, C>>::get(reader)?;
match byte {
DropCounted::TAG_BYTE => {
dst.write(DropCountedMaybeError::DropCounted(DropCounted::new()));
Ok(())
}
ErrorsOnRead::TAG_BYTE => Err(error::ReadError::PointerSizedReadError),
_ => Err(invalid_tag_encoding(byte as usize)),
}
}
}
#[test]
fn drop_count_sanity() {
let _guard = TLDropGuard::new();
let serialized = { serialize(&[DropCounted::new(), DropCounted::new()]).unwrap() };
let _deserialized: [DropCounted; 2] = deserialize(&serialized).unwrap();
assert_eq!(get_tl_drop_count(), 2);
}
#[test]
fn drop_count_maybe_error_sanity() {
let _guard = TLDropGuard::new();
let serialized =
{ serialize(&[DropCountedMaybeError::DropCounted(DropCounted::new())]).unwrap() };
let _deserialized: [DropCountedMaybeError; 1] = deserialize(&serialized).unwrap();
assert_eq!(get_tl_drop_count(), 1);
let serialized = {
serialize(&[
DropCountedMaybeError::DropCounted(DropCounted::new()),
DropCountedMaybeError::ErrorsOnRead(ErrorsOnRead),
])
.unwrap()
};
let _deserialized: ReadResult<[DropCountedMaybeError; 2]> = deserialize(&serialized);
}
#[test]
fn test_struct_derive_handles_partial_drop() {
#[derive(SchemaWrite, SchemaRead, proptest_derive::Arbitrary, Debug, PartialEq, Eq)]
#[wincode(internal)]
struct CouldLeak {
data: DropCountedMaybeError,
data2: DropCountedMaybeError,
data3: DropCountedMaybeError,
}
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(could_leak: CouldLeak)| {
let serialized = serialize(&could_leak).unwrap();
let deserialized = CouldLeak::deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(could_leak, deserialized);
}
});
}
#[test]
fn test_vec_of_references_borrows_from_input() {
#[derive(
SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy,
)]
#[wincode(internal)]
#[repr(transparent)]
struct BigBytes([u8; 512]);
proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<BigBytes>(), 0..=8))| {
let bytes = serialize(&vec).unwrap();
let borrowed: Vec<&BigBytes> = deserialize(&bytes).unwrap();
prop_assert_eq!(borrowed.len(), vec.len());
let start = bytes.as_ptr().addr();
let end = start + bytes.len();
for (i, r) in borrowed.iter().enumerate() {
prop_assert_eq!(**r, vec[i]);
let p = ptr::from_ref(*r).addr();
prop_assert!(p >= start && p < end);
}
});
}
#[test]
fn test_boxed_slice_of_references_borrows_from_input() {
#[derive(
SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy,
)]
#[wincode(internal)]
#[repr(transparent)]
struct BigBytes([u8; 512]);
proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<BigBytes>(), 0..=8))| {
let boxed: Box<[BigBytes]> = vec.into_boxed_slice();
let bytes = serialize(&boxed).unwrap();
let borrowed: Box<[&BigBytes]> = deserialize(&bytes).unwrap();
prop_assert_eq!(borrowed.len(), boxed.len());
let start = bytes.as_ptr().addr();
let end = start + bytes.len();
for (i, &r) in borrowed.iter().enumerate() {
prop_assert_eq!(*r, boxed[i]);
let p = ptr::from_ref(r).addr();
prop_assert!(p >= start && p < end);
}
});
}
#[test]
fn test_enum_derive_handles_partial_drop() {
#[derive(SchemaWrite, SchemaRead, proptest_derive::Arbitrary, Debug, PartialEq, Eq)]
#[wincode(internal)]
enum CouldLeak {
A {
a: DropCountedMaybeError,
b: DropCountedMaybeError,
},
B(
DropCountedMaybeError,
DropCountedMaybeError,
DropCountedMaybeError,
),
C(DropCountedMaybeError),
D,
}
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(could_leak: CouldLeak)| {
let serialized = serialize(&could_leak).unwrap();
let deserialized = CouldLeak::deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(could_leak, deserialized);
}
});
}
#[test]
fn test_tuple_handles_partial_drop() {
let _guard = TLDropGuard::new();
let serialized =
{ serialize(&(DropCounted::new(), DropCounted::new(), ErrorsOnRead)).unwrap() };
let deserialized: ReadResult<(DropCounted, DropCounted, ErrorsOnRead)> =
deserialize(&serialized);
assert!(deserialized.is_err());
}
#[test]
fn test_vec_handles_partial_drop() {
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100))| {
let serialized = serialize(&vec).unwrap();
let deserialized = <Vec<DropCountedMaybeError>>::deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(vec, deserialized);
}
});
}
#[test]
fn test_vec_deque_handles_partial_drop() {
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(vec in proptest::collection::vec_deque(any::<DropCountedMaybeError>(), 0..100))| {
let serialized = serialize(&vec).unwrap();
let deserialized = <VecDeque<DropCountedMaybeError>>::deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(vec, deserialized);
}
});
}
#[test]
fn test_boxed_slice_handles_partial_drop() {
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100).prop_map(|vec| vec.into_boxed_slice()))| {
let serialized = serialize(&slice).unwrap();
let deserialized = <Box<[DropCountedMaybeError]>>::deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(slice, deserialized);
}
});
}
#[test]
fn test_rc_slice_handles_partial_drop() {
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100).prop_map(Rc::from))| {
let serialized = serialize(&slice).unwrap();
let deserialized = <Rc<[DropCountedMaybeError]>>::deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(slice, deserialized);
}
});
}
#[test]
fn test_arc_slice_handles_partial_drop() {
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100).prop_map(Arc::from))| {
let serialized = serialize(&slice).unwrap();
let deserialized = <Arc<[DropCountedMaybeError]>>::deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(slice, deserialized);
}
});
}
#[test]
fn test_arc_handles_drop() {
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(data in any::<DropCountedMaybeError>().prop_map(Rc::from))| {
let serialized = serialize(&data).unwrap();
let deserialized = deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(data, deserialized);
}
});
}
#[test]
fn test_rc_handles_drop() {
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(data in any::<DropCountedMaybeError>().prop_map(Rc::from))| {
let serialized = serialize(&data).unwrap();
let deserialized = deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(data, deserialized);
}
});
}
#[test]
fn test_box_handles_drop() {
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(data in any::<DropCountedMaybeError>().prop_map(Box::new))| {
let serialized = serialize(&data).unwrap();
let deserialized = deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(data, deserialized);
}
});
}
#[test]
fn test_array_handles_partial_drop() {
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(array in proptest::array::uniform32(any::<DropCountedMaybeError>()))| {
let serialized = serialize(&array).unwrap();
let deserialized = <[DropCountedMaybeError; 32]>::deserialize(&serialized);
if let Ok(deserialized) = deserialized {
prop_assert_eq!(array, deserialized);
}
});
}
#[test]
fn test_uninit_builder_handles_partial_drop() {
#[derive(SchemaWrite, UninitBuilder, Debug, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct Test {
a: DropCounted,
b: DropCounted,
c: DropCounted,
}
{
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(test: Test)| {
let serialized = serialize(&test).unwrap();
let mut test = MaybeUninit::<Test>::uninit();
let mut reader = serialized.as_slice();
let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut test);
builder.read_a(reader.by_ref())?.read_b(reader.by_ref())?;
prop_assert!(!builder.is_init());
});
}
#[derive(SchemaWrite, UninitBuilder, Debug, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct TestTuple(DropCounted, DropCounted);
{
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(test: TestTuple)| {
let serialized = serialize(&test).unwrap();
let mut test = MaybeUninit::<TestTuple>::uninit();
let reader = &mut serialized.as_slice();
let mut builder = TestTupleUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut test);
builder.read_0(reader)?;
prop_assert!(!builder.is_init());
});
}
}
#[test]
fn test_uninit_builder_nested_builder_handles_partial_drop() {
#[derive(SchemaWrite, SchemaRead, UninitBuilder, Debug, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct Inner {
a: DropCounted,
b: DropCounted,
c: DropCounted,
}
#[derive(SchemaWrite, UninitBuilder, Debug, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct Test {
inner: Inner,
b: DropCounted,
}
{
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(test: Test)| {
let serialized = serialize(&test).unwrap();
let mut test = MaybeUninit::<Test>::uninit();
let mut reader = serialized.as_slice();
let mut outer_builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut test);
unsafe {
outer_builder.init_inner_with(|inner| {
let mut inner_builder = InnerUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(inner);
inner_builder.read_a(reader.by_ref())?;
inner_builder.read_b(reader.by_ref())?;
inner_builder.read_c(reader.by_ref())?;
assert!(inner_builder.is_init());
inner_builder.finish();
Ok(())
})?;
}
});
}
}
#[test]
fn test_uninit_builder_nested_fully_initialized() {
#[derive(
SchemaWrite, SchemaRead, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary,
)]
#[wincode(internal)]
struct Inner {
a: DropCounted,
b: DropCounted,
c: DropCounted,
}
#[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct Test {
inner: Inner,
b: DropCounted,
}
{
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(test: Test)| {
let serialized = serialize(&test).unwrap();
let mut uninit = MaybeUninit::<Test>::uninit();
let mut reader = serialized.as_slice();
let mut outer_builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
unsafe {
outer_builder.init_inner_with(|inner| {
let mut inner_builder = InnerUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(inner);
inner_builder.read_a(reader.by_ref())?;
inner_builder.read_b(reader.by_ref())?;
inner_builder.read_c(reader.by_ref())?;
assert!(inner_builder.is_init());
inner_builder.finish();
Ok(())
})?;
}
outer_builder.read_b(reader.by_ref())?;
prop_assert!(outer_builder.is_init());
outer_builder.finish();
let init = unsafe { uninit.assume_init() };
prop_assert_eq!(test, init);
});
}
}
#[test]
fn test_uninit_builder() {
#[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct Test {
a: Vec<u8>,
b: [u8; 32],
c: u64,
}
proptest!(proptest_cfg(), |(test: Test)| {
let serialized = serialize(&test).unwrap();
let mut uninit = MaybeUninit::<Test>::uninit();
let mut reader = serialized.as_slice();
let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
builder
.read_a(reader.by_ref())?
.read_b(reader.by_ref())?
.write_c(test.c);
prop_assert!(builder.is_init());
builder.finish();
let init = unsafe { uninit.assume_init() };
prop_assert_eq!(test, init);
});
}
#[test]
fn test_uninit_builder_uninit_ref() {
#[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct Test {
a: Vec<u8>,
b: [u8; 32],
c: u64,
}
proptest!(proptest_cfg(), |(test: Test)| {
let serialized = serialize(&test).unwrap();
let mut uninit = MaybeUninit::<Test>::uninit();
let mut reader = serialized.as_slice();
let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
builder
.read_a(reader.by_ref())?
.read_b(reader.by_ref())?
.write_c(test.c);
prop_assert!(builder.is_init());
unsafe {
prop_assert_eq!(builder.uninit_a_ref().assume_init_ref(), &test.a);
prop_assert_eq!(builder.uninit_b_ref().assume_init_ref(), &test.b);
prop_assert_eq!(builder.uninit_c_ref().assume_init_ref(), &test.c);
}
builder.finish();
let init = unsafe { uninit.assume_init() };
prop_assert_eq!(test, init);
});
}
#[test]
#[allow(deprecated)]
fn test_struct_extensions_sanity() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal, struct_extensions)]
struct Test {
a: Vec<u8>,
b: [u8; 32],
c: u64,
}
proptest!(proptest_cfg(), |(test: Test)| {
let serialized = serialize(&test).unwrap();
let mut uninit = MaybeUninit::<Test>::uninit();
let mut reader = serialized.as_slice();
let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
builder
.read_a(reader.by_ref())?
.read_b(reader.by_ref())?
.write_c(test.c);
prop_assert!(builder.is_init());
builder.finish();
let init = unsafe { uninit.assume_init() };
prop_assert_eq!(test, init);
});
}
#[test]
fn test_uninit_builder_with_container() {
#[derive(UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct Test {
#[wincode(with = "containers::Vec<_, BincodeLen>")]
a: Vec<u8>,
b: [u8; 32],
c: u64,
}
proptest!(proptest_cfg(), |(test: Test)| {
let mut uninit = MaybeUninit::<Test>::uninit();
let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
builder
.write_a(test.a.clone())
.write_b(test.b)
.write_c(test.c);
prop_assert!(builder.is_init());
let init_mut = unsafe { builder.into_assume_init_mut() };
prop_assert_eq!(&test, init_mut);
let init = unsafe { uninit.assume_init() };
prop_assert_eq!(test, init);
});
}
#[test]
fn test_uninit_builder_extensions_with_reference() {
#[derive(Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
struct Test {
a: Vec<u8>,
b: Option<String>,
}
#[derive(UninitBuilder, Debug, PartialEq, Eq)]
#[wincode(internal)]
struct TestRef<'a> {
a: &'a [u8],
b: Option<&'a str>,
}
proptest!(proptest_cfg(), |(test: Test)| {
let mut uninit = MaybeUninit::<TestRef>::uninit();
let mut builder = TestRefUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
builder
.write_a(test.a.as_slice())
.write_b(test.b.as_deref());
prop_assert!(builder.is_init());
builder.finish();
let init = unsafe { uninit.assume_init() };
prop_assert_eq!(test.a.as_slice(), init.a);
prop_assert_eq!(test.b.as_deref(), init.b);
});
}
#[test]
fn test_uninit_builder_with_mapped_type() {
#[derive(Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
struct Test {
a: Vec<u8>,
b: [u8; 32],
c: u64,
}
#[derive(UninitBuilder)]
#[wincode(internal, from = "Test")]
#[allow(unused)]
struct TestMapped {
a: containers::Vec<u8, BincodeLen>,
b: [u8; 32],
c: u64,
}
proptest!(proptest_cfg(), |(test: Test)| {
let mut uninit = MaybeUninit::<Test>::uninit();
let mut builder = TestMappedUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
builder
.write_a(test.a.clone())
.write_b(test.b)
.write_c(test.c);
prop_assert!(builder.is_init());
builder.finish();
let init = unsafe { uninit.assume_init() };
prop_assert_eq!(test, init);
});
}
#[test]
fn test_uninit_builder_builder_fully_initialized() {
#[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct Test {
a: DropCounted,
b: DropCounted,
c: DropCounted,
}
{
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(test: Test)| {
let serialized = serialize(&test).unwrap();
let mut uninit = MaybeUninit::<Test>::uninit();
let mut reader = serialized.as_slice();
let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
builder
.read_a(reader.by_ref())?
.read_b(reader.by_ref())?
.read_c(reader.by_ref())?;
prop_assert!(builder.is_init());
let init = unsafe { builder.into_assume_init_mut() };
prop_assert_eq!(&test, init);
let init = unsafe { uninit.assume_init() };
prop_assert_eq!(test, init);
});
}
#[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct TestTuple(DropCounted, DropCounted);
{
let _guard = TLDropGuard::new();
proptest!(proptest_cfg(), |(test: TestTuple)| {
let serialized = serialize(&test).unwrap();
let mut uninit = MaybeUninit::<TestTuple>::uninit();
let mut reader = serialized.as_slice();
let mut builder = TestTupleUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
builder
.read_0(reader.by_ref())?
.read_1(reader.by_ref())?;
assert!(builder.is_init());
builder.finish();
let init = unsafe { uninit.assume_init() };
prop_assert_eq!(test, init);
});
}
}
#[test]
#[cfg(feature = "solana-short-vec")]
fn test_uninit_builder_with() {
use crate::len::ShortU16;
#[derive(
SchemaWrite,
UninitBuilder,
Debug,
PartialEq,
Eq,
proptest_derive::Arbitrary,
serde::Serialize,
serde::Deserialize,
)]
#[wincode(internal)]
struct Test {
#[wincode(with = "containers::Vec<u8, ShortU16>")]
#[serde(with = "solana_short_vec")]
foo: Vec<u8>,
}
proptest!(proptest_cfg(), |(test: Test)| {
let serialized = serialize(&test).unwrap();
let bincode_serialized = bincode::serialize(&test).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let bincode_deserialized: Test = bincode::deserialize(&bincode_serialized).unwrap();
let mut uninit = MaybeUninit::<Test>::uninit();
let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
let mut reader = serialized.as_slice();
builder.read_foo(reader.by_ref())?;
builder.finish();
let deserialized = unsafe { uninit.assume_init() };
prop_assert_eq!(&test, &bincode_deserialized);
prop_assert_eq!(test, deserialized);
});
}
#[test]
fn test_struct_with_reference_equivalence() {
#[derive(
SchemaWrite, SchemaRead, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize,
)]
#[wincode(internal)]
struct WithReference<'a> {
data: &'a str,
id: u64,
}
proptest!(proptest_cfg(), |(s in any::<String>(), id in any::<u64>())| {
let serialized = serialize(&WithReference { data: &s, id }).unwrap();
let bincode_serialized = bincode::serialize(&WithReference { data: &s, id }).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: WithReference = deserialize(&serialized).unwrap();
let bincode_deserialized: WithReference = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(deserialized, bincode_deserialized);
});
}
#[test]
fn test_skipped_fields() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct Test {
a: StructZeroCopy,
#[wincode(skip)]
b: [u8; 32],
c: StructStatic,
#[wincode(skip(default_val = 345))]
d: u32,
}
let expected = TypeMeta::Static {
size: size_of::<StructZeroCopy>()
+ <StructStatic as SchemaWrite<DefaultConfig>>::TYPE_META.size_assert_static(),
zero_copy: false,
};
assert_eq!(<Test as SchemaWrite<DefaultConfig>>::TYPE_META, expected);
proptest!(proptest_cfg(), |(test: Test)| {
let mut serialized = serialize(&test).unwrap();
let mut uninit_zeroed = MaybeUninit::<Test>::uninit();
Test::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
let deserialized = unsafe { uninit_zeroed.assume_init() };
assert_eq!(deserialized.b, [0; 32]);
assert_eq!(deserialized.d, 345);
let reinitialized = Test {
b: test.b,
d: test.d,
..deserialized
};
prop_assert_eq!(reinitialized, test);
});
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct TestTuple(StructZeroCopy, #[wincode(skip)] u64, u32);
let expected = TypeMeta::Static {
size: size_of::<StructZeroCopy>() + size_of::<u32>(),
zero_copy: false,
};
assert_eq!(
<TestTuple as SchemaWrite<DefaultConfig>>::TYPE_META,
expected
);
proptest!(proptest_cfg(), |(test: TestTuple)| {
let mut serialized = serialize(&test).unwrap();
let mut uninit_zeroed = MaybeUninit::<TestTuple>::uninit();
TestTuple::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
let deserialized = unsafe { uninit_zeroed.assume_init() };
assert_eq!(deserialized.1, 0);
let reinitialized = TestTuple(deserialized.0, test.1, deserialized.2);
prop_assert_eq!(reinitialized, test);
});
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
enum TestEnum {
X([u64; 17], u8),
Y(Test),
Z(([u64; 16], u8), #[wincode(skip(default_val = 9))] u8, u64),
W {
a: u8,
#[wincode(skip(default_val = 123))]
b: u16,
c: [u64; 17],
},
}
let expected = TypeMeta::Static {
size: size_of::<u32>() + size_of::<u64>() * 17 + size_of::<u8>(),
zero_copy: false,
};
assert_eq!(
<TestEnum as SchemaWrite<DefaultConfig>>::TYPE_META,
expected
);
proptest!(proptest_cfg(), |(test: TestEnum)| {
let mut serialized = serialize(&test).unwrap();
let mut uninit_zeroed = MaybeUninit::<TestEnum>::uninit();
TestEnum::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
let deserialized = unsafe { uninit_zeroed.assume_init() };
let reinitialized = match (deserialized, &test) {
(TestEnum::Y(deserialized_y), TestEnum::Y(test_y)) => {
assert_eq!(deserialized_y.b, [0; 32]);
assert_eq!(deserialized_y.d, 345);
TestEnum::Y(Test {
b: test_y.b,
d: test_y.d,
..deserialized_y
})
},
(TestEnum::Z(d_0, d_1, d_2), TestEnum::Z(_, t_1, _)) => {
assert_eq!(d_1, 9);
TestEnum::Z(d_0, *t_1, d_2)
},
(TestEnum::W { a: d_a, b: d_b, c: d_c }, TestEnum::W { a: _, b: test_b, c: _ }) => {
assert_eq!(d_b, 123);
TestEnum::W {
a: d_a,
b: *test_b,
c: d_c,
}
},
(other, _) => other
};
prop_assert_eq!(reinitialized, test);
});
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
#[repr(C)]
struct TestZeroCopy {
a: StructZeroCopy,
#[wincode(skip)]
b: (),
c: [u8; 16],
}
assert_eq!(
<TestZeroCopy as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: size_of::<StructZeroCopy>() + 16,
zero_copy: true,
}
);
proptest!(proptest_cfg(), |(test: TestZeroCopy)| {
let mut serialized = serialize(&test).unwrap();
let mut uninit_zeroed = MaybeUninit::<TestZeroCopy>::uninit();
TestZeroCopy::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
let deserialized = unsafe { uninit_zeroed.assume_init() };
prop_assert_eq!(deserialized, test);
});
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
#[repr(C)]
struct TestNonZeroCopy {
a: StructZeroCopy,
#[wincode(skip(default_val = [1u8; 16]))]
b: [u8; 16],
}
assert_eq!(
<TestNonZeroCopy as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: size_of::<StructZeroCopy>(),
zero_copy: false,
}
);
proptest!(proptest_cfg(), |(test: TestNonZeroCopy)| {
let mut serialized = serialize(&test).unwrap();
let mut uninit_zeroed = MaybeUninit::<TestNonZeroCopy>::uninit();
TestNonZeroCopy::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
let deserialized = unsafe { uninit_zeroed.assume_init() };
assert_eq!(deserialized.b, [1u8; 16]);
let reinitialized = TestNonZeroCopy {
b: test.b,
..deserialized
};
prop_assert_eq!(reinitialized, test);
});
}
#[test]
fn test_enum_equivalence() {
#[derive(
SchemaWrite,
SchemaRead,
Debug,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
Clone,
proptest_derive::Arbitrary,
)]
#[wincode(internal)]
enum Enum {
A { name: String, id: u64 },
B(String, Vec<u8>),
C,
}
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = serialize(&e).unwrap();
let bincode_serialized = bincode::serialize(&e).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: Enum = deserialize(&serialized).unwrap();
let bincode_deserialized: Enum = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(deserialized, bincode_deserialized);
});
}
#[test]
fn enum_with_tag_encoding_roundtrip() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
#[wincode(internal, tag_encoding = "u8")]
enum Enum {
A { name: String, id: u64 },
B(String, Vec<u8>),
C,
}
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = serialize(&e).unwrap();
let deserialized: Enum = deserialize(&serialized).unwrap();
prop_assert_eq!(deserialized, e);
});
}
#[test]
fn enum_with_custom_tag_roundtrip() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
#[wincode(internal)]
enum Enum {
#[wincode(tag = 5)]
A { name: String, id: u64 },
#[wincode(tag = 8)]
B(String, Vec<u8>),
#[wincode(tag = 13)]
C,
}
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = serialize(&e).unwrap();
let deserialized: Enum = deserialize(&serialized).unwrap();
prop_assert_eq!(deserialized, e);
});
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = serialize(&e).unwrap();
let int: u32 = match e {
Enum::A { .. } => 5,
Enum::B(..) => 8,
Enum::C => 13,
};
prop_assert_eq!(&int.to_le_bytes(), &serialized[..4]);
});
}
#[test]
fn unit_enum_with_tag_encoding_static_size() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq)]
#[wincode(internal, tag_encoding = "u8")]
enum Enum {
A,
B,
C,
}
assert!(matches!(
<Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 1,
zero_copy: false
}
));
assert!(matches!(
<Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 1,
zero_copy: false
}
));
}
#[test]
fn unit_enum_with_static_size() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq)]
#[wincode(internal)]
enum Enum {
A,
B,
C,
}
assert!(matches!(
<Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 4,
zero_copy: false
}
));
assert!(matches!(
<Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 4,
zero_copy: false
}
));
}
#[test]
fn enum_tag_encoding() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
#[wincode(internal, tag_encoding = "u8")]
enum EnumU8 {
A,
B,
C,
}
proptest!(proptest_cfg(), |(e: EnumU8)| {
let serialized = serialize(&e).unwrap();
let int = e as u8;
prop_assert_eq!(&int.to_le_bytes(), &serialized[..]);
});
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
#[wincode(internal, tag_encoding = "u8")]
enum EnumTupleU8 {
A(u64),
B(StructStatic),
C(StructNonStatic),
}
proptest!(proptest_cfg(), |(e: EnumTupleU8)| {
let serialized = serialize(&e).unwrap();
let int: u8 = match e {
EnumTupleU8::A(_) => 0,
EnumTupleU8::B(_) => 1,
EnumTupleU8::C(_) => 2,
};
prop_assert_eq!(&int.to_le_bytes(), &serialized[..1]);
});
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
#[wincode(internal, tag_encoding = "u8")]
enum EnumRecordU8 {
A { id: u64 },
B { data: StructStatic },
C { data: StructNonStatic },
}
proptest!(proptest_cfg(), |(e: EnumRecordU8)| {
let serialized = serialize(&e).unwrap();
let int: u8 = match e {
EnumRecordU8::A { .. } => 0,
EnumRecordU8::B { .. } => 1,
EnumRecordU8::C { .. } => 2,
};
prop_assert_eq!(&int.to_le_bytes(), &serialized[..1]);
});
}
#[test]
fn enum_static_uniform_variants() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
#[wincode(internal)]
enum Enum {
A {
a: u64,
},
B {
x: u32,
y: u32,
},
C {
a: u8,
b: u8,
c: u8,
d: u8,
e: u8,
f: u8,
g: u8,
h: u8,
},
}
assert_eq!(
<Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 8 + 4,
zero_copy: false
}
);
assert_eq!(
<Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 8 + 4,
zero_copy: false
}
);
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = serialize(&e).unwrap();
let deserialized: Enum = deserialize(&serialized).unwrap();
prop_assert_eq!(deserialized, e);
});
}
#[test]
fn enum_dynamic_non_uniform_variants() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
#[wincode(internal)]
enum Enum {
A { a: u64 },
B { x: u32, y: u32 },
C { a: u8, b: u8 },
}
assert_eq!(
<Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Dynamic
);
assert_eq!(
<Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
TypeMeta::Dynamic
);
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = serialize(&e).unwrap();
let deserialized: Enum = deserialize(&serialized).unwrap();
prop_assert_eq!(deserialized, e);
});
}
#[test]
fn enum_single_variant_type_meta_pass_thru() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
#[wincode(internal)]
enum Enum {
A { a: u8, b: [u8; 32] },
}
assert_eq!(
<Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 1 + 32 + 4,
zero_copy: false
}
);
assert_eq!(
<Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 1 + 32 + 4,
zero_copy: false
}
);
}
#[test]
fn enum_unit_and_non_unit_dynamic() {
#[derive(
SchemaWrite,
SchemaRead,
Debug,
PartialEq,
proptest_derive::Arbitrary,
serde::Serialize,
serde::Deserialize,
)]
#[wincode(internal)]
enum Enum {
Unit,
NonUnit(u8),
}
assert_eq!(
<Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Dynamic
);
assert_eq!(
<Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
TypeMeta::Dynamic
);
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = serialize(&e).unwrap();
let bincode_serialized = bincode::serialize(&e).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: Enum = deserialize(&serialized).unwrap();
let bincode_deserialized: Enum = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(deserialized, e);
});
}
#[test]
fn test_enum_config_discriminant_u8() {
let config = Configuration::default().with_tag_encoding::<u8>();
#[derive(SchemaRead, SchemaWrite, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
enum Enum {
A,
B,
}
assert_eq!(
<Enum as SchemaRead<'_, _>>::type_meta(config),
TypeMeta::Static {
size: 1,
zero_copy: false
}
);
assert_eq!(
<Enum as SchemaWrite<_>>::type_meta(config),
TypeMeta::Static {
size: 1,
zero_copy: false
}
);
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = config::serialize(&e, config).unwrap();
prop_assert_eq!(serialized.len(), 1);
match e {
Enum::A => prop_assert_eq!(serialized[0], 0),
Enum::B => prop_assert_eq!(serialized[0], 1),
}
let deserialized: Enum = config::deserialize(&serialized, config).unwrap();
prop_assert_eq!(deserialized, e);
});
}
#[test]
fn test_enum_config_discriminant_override() {
let config = Configuration::default().with_tag_encoding::<u8>();
#[derive(SchemaRead, SchemaWrite, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal, tag_encoding = "u32")]
enum Enum {
A,
B,
}
assert_eq!(
<Enum as SchemaRead<'_, _>>::type_meta(config),
TypeMeta::Static {
size: 4,
zero_copy: false
}
);
assert_eq!(
<Enum as SchemaWrite<_>>::type_meta(config),
TypeMeta::Static {
size: 4,
zero_copy: false
}
);
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = config::serialize(&e, config).unwrap();
prop_assert_eq!(serialized.len(), 4);
let discriminant = u32::from_le_bytes(serialized[0..4].try_into().unwrap());
match e {
Enum::A => prop_assert_eq!(discriminant, 0u32),
Enum::B => prop_assert_eq!(discriminant, 1u32),
}
let deserialized: Enum = config::deserialize(&serialized, config).unwrap();
prop_assert_eq!(deserialized, e);
});
}
#[test]
fn test_enum_config_discriminant_u8_custom_tag() {
let config = Configuration::default().with_tag_encoding::<u8>();
#[derive(SchemaRead, SchemaWrite, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
enum Enum {
#[wincode(tag = 2)]
A,
#[wincode(tag = 3)]
B,
#[wincode(tag = 5)]
C,
}
proptest!(proptest_cfg(), |(e: Enum)| {
let serialized = config::serialize(&e, config).unwrap();
prop_assert_eq!(serialized.len(), 1);
match e {
Enum::A => prop_assert_eq!(serialized[0], 2),
Enum::B => prop_assert_eq!(serialized[0], 3),
Enum::C => prop_assert_eq!(serialized[0], 5),
}
let deserialized: Enum = config::deserialize(&serialized, config).unwrap();
prop_assert_eq!(deserialized, e);
});
}
#[test]
fn test_phantom_data() {
let val = PhantomData::<StructStatic>;
let serialized = serialize(&val).unwrap();
let bincode_serialized = bincode::serialize(&val).unwrap();
assert_eq!(&serialized, &bincode_serialized);
assert_eq!(
<PhantomData<StructStatic> as SchemaWrite<DefaultConfig>>::size_of(&val).unwrap(),
bincode::serialized_size(&val).unwrap() as usize
);
let deserialized: PhantomData<StructStatic> = deserialize(&serialized).unwrap();
let bincode_deserialized: PhantomData<StructStatic> =
bincode::deserialize(&bincode_serialized).unwrap();
assert_eq!(deserialized, bincode_deserialized);
}
#[test]
fn test_unit() {
let serialized = serialize(&()).unwrap();
let bincode_serialized = bincode::serialize(&()).unwrap();
assert_eq!(&serialized, &bincode_serialized);
assert_eq!(
<() as SchemaWrite<DefaultConfig>>::size_of(&()).unwrap(),
bincode::serialized_size(&()).unwrap() as usize
);
assert!(deserialize::<()>(&serialized).is_ok());
assert!(bincode::deserialize::<()>(&bincode_serialized).is_ok());
}
#[test]
fn test_duration_varint_type_meta_dynamic() {
let config = Configuration::default().with_varint_encoding();
assert_eq!(
<Duration as SchemaWrite<_>>::type_meta(config),
TypeMeta::Dynamic
);
assert_eq!(
<Duration as SchemaRead<'_, _>>::type_meta(config),
TypeMeta::Dynamic
);
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
#[wincode(internal)]
struct WithDuration {
a: u8,
d: Duration,
b: u8,
}
assert_eq!(
<WithDuration as SchemaWrite<_>>::type_meta(config),
TypeMeta::Dynamic
);
assert_eq!(
<WithDuration as SchemaRead<'_, _>>::type_meta(config),
TypeMeta::Dynamic
);
let val = WithDuration {
a: 1,
d: Duration::new(0, 0),
b: 2,
};
assert_eq!(config::serialized_size(&val.d, config).unwrap(), 2);
let mut buf = [0xAAu8; 13];
let written = {
let buf_len = buf.len();
let mut writer: &mut [u8] = &mut buf;
config::serialize_into(&mut writer, &val, config).unwrap();
buf_len - writer.len()
};
assert_eq!(written, 4);
assert_eq!(&buf[..written], &[1, 0, 0, 2]);
assert!(buf[written..].iter().all(|&b| b == 0xAA));
let roundtrip: WithDuration = config::deserialize(&buf[..written], config).unwrap();
assert_eq!(roundtrip, val);
}
#[test]
fn test_system_time_varint_type_meta_dynamic() {
let config = Configuration::default().with_varint_encoding();
assert_eq!(
<SystemTime as SchemaWrite<_>>::type_meta(config),
TypeMeta::Dynamic
);
assert_eq!(
<SystemTime as SchemaRead<'_, _>>::type_meta(config),
TypeMeta::Dynamic
);
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
#[wincode(internal)]
struct WithSystemTime {
a: u8,
t: SystemTime,
b: u8,
}
assert_eq!(
<WithSystemTime as SchemaWrite<_>>::type_meta(config),
TypeMeta::Dynamic
);
assert_eq!(
<WithSystemTime as SchemaRead<'_, _>>::type_meta(config),
TypeMeta::Dynamic
);
let val = WithSystemTime {
a: 1,
t: UNIX_EPOCH,
b: 2,
};
assert_eq!(config::serialized_size(&val.t, config).unwrap(), 2);
let mut buf = [0xAAu8; 13];
let written = {
let buf_len = buf.len();
let mut writer: &mut [u8] = &mut buf;
config::serialize_into(&mut writer, &val, config).unwrap();
buf_len - writer.len()
};
assert_eq!(written, 4);
assert_eq!(&buf[..written], &[1, 0, 0, 2]);
assert!(buf[written..].iter().all(|&b| b == 0xAA));
let roundtrip: WithSystemTime = config::deserialize(&buf[..written], config).unwrap();
assert_eq!(roundtrip, val);
}
#[test]
fn test_borrowed_bytes() {
#[derive(
SchemaWrite, SchemaRead, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize,
)]
#[wincode(internal)]
struct BorrowedBytes<'a> {
bytes: &'a [u8],
}
proptest!(proptest_cfg(), |(bytes in proptest::collection::vec(any::<u8>(), 0..=100))| {
let val = BorrowedBytes { bytes: &bytes };
let bincode_serialized = bincode::serialize(&val).unwrap();
let schema_serialized = serialize(&val).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: BorrowedBytes = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: BorrowedBytes = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&val, &bincode_deserialized);
prop_assert_eq!(val, schema_deserialized);
});
}
#[test]
fn test_boxed_slice_pod_drop() {
#[derive(proptest_derive::Arbitrary, Debug, Clone, Copy)]
#[allow(dead_code)]
struct Signature([u8; 64]);
pod_wrapper! {
unsafe struct PodSignature(Signature);
}
type Target = containers::Box<[PodSignature], BincodeLen>;
proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<Signature>(), 1..=32).prop_map(|vec| vec.into_boxed_slice()))| {
let serialized = Target::serialize(&slice).unwrap();
let deserialized = Target::deserialize(&serialized[..serialized.len() - 32]);
prop_assert!(deserialized.is_err());
});
}
#[test]
fn test_zero_copy_padding_disqualification() {
#[derive(SchemaWrite, SchemaRead)]
#[wincode(internal)]
#[repr(C, align(4))]
struct Padded {
a: u8,
}
assert!(matches!(
<Padded as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 1,
zero_copy: false
}
));
assert!(matches!(
<Padded as SchemaRead<'_, DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 1,
zero_copy: false
}
));
}
proptest! {
#![proptest_config(proptest_cfg())]
#[test]
fn test_char(val in any::<char>()) {
let bincode_serialized = bincode::serialize(&val).unwrap();
let schema_serialized = serialize(&val).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
prop_assert_eq!(<char as SchemaWrite<DefaultConfig>>::size_of(&val).unwrap(), bincode::serialized_size(&val).unwrap() as usize);
let bincode_deserialized: char = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: char = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(val, bincode_deserialized);
prop_assert_eq!(val, schema_deserialized);
}
#[test]
fn test_vec_elem_static(vec in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&vec).unwrap();
let schema_serialized = serialize(&vec).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Vec<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Vec<StructStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&vec, &bincode_deserialized);
prop_assert_eq!(vec, schema_deserialized);
}
#[test]
fn test_vec_elem_zero_copy(vec in proptest::collection::vec(any::<StructZeroCopy>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&vec).unwrap();
let schema_serialized = serialize(&vec).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Vec<StructZeroCopy> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Vec<StructZeroCopy> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&vec, &bincode_deserialized);
prop_assert_eq!(vec, schema_deserialized);
}
#[test]
fn test_vec_elem_non_static(vec in proptest::collection::vec(any::<StructNonStatic>(), 0..=16)) {
let bincode_serialized = bincode::serialize(&vec).unwrap();
let schema_serialized = serialize(&vec).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Vec<StructNonStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Vec<StructNonStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&vec, &bincode_deserialized);
prop_assert_eq!(vec, schema_deserialized);
}
#[test]
fn test_vec_elem_bytes(vec in proptest::collection::vec(any::<u8>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&vec).unwrap();
let schema_serialized = serialize(&vec).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Vec<u8> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Vec<u8> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&vec, &bincode_deserialized);
prop_assert_eq!(vec, schema_deserialized);
}
#[test]
fn test_serialize_slice(slice in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
let bincode_serialized = bincode::serialize(slice.as_slice()).unwrap();
let schema_serialized = serialize(slice.as_slice()).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
}
#[test]
fn test_vec_pod(vec in proptest::collection::vec(any::<[u8; 32]>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&vec).unwrap();
let schema_serialized = serialize(&vec).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Vec<[u8; 32]> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Vec<[u8; 32]> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&vec, &bincode_deserialized);
prop_assert_eq!(vec, schema_deserialized);
}
#[test]
fn test_vec_deque_elem_static(vec in proptest::collection::vec_deque(any::<StructStatic>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&vec).unwrap();
let schema_serialized = serialize(&vec).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: VecDeque<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: VecDeque<StructStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&vec, &bincode_deserialized);
prop_assert_eq!(vec, schema_deserialized);
}
#[test]
fn test_vec_deque_elem_non_static(vec in proptest::collection::vec_deque(any::<StructNonStatic>(), 0..=16)) {
let bincode_serialized = bincode::serialize(&vec).unwrap();
let schema_serialized = serialize(&vec).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: VecDeque<StructNonStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: VecDeque<StructNonStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&vec, &bincode_deserialized);
prop_assert_eq!(vec, schema_deserialized);
}
#[test]
fn test_vec_deque_elem_bytes(vec in proptest::collection::vec_deque(any::<u8>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&vec).unwrap();
let schema_serialized = serialize(&vec).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: VecDeque<u8> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: VecDeque<u8> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&vec, &bincode_deserialized);
prop_assert_eq!(vec, schema_deserialized);
}
#[test]
fn test_hash_map_zero_copy(map in proptest::collection::hash_map(any::<u8>(), any::<StructZeroCopy>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&map).unwrap();
let schema_serialized = serialize(&map).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&map, &bincode_deserialized);
prop_assert_eq!(map, schema_deserialized);
}
#[test]
fn test_hash_map_static(map in proptest::collection::hash_map(any::<u64>(), any::<StructStatic>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&map).unwrap();
let schema_serialized = serialize(&map).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&map, &bincode_deserialized);
prop_assert_eq!(map, schema_deserialized);
}
#[test]
fn test_hash_map_non_static(map in proptest::collection::hash_map(any::<u64>(), any::<StructNonStatic>(), 0..=16)) {
let bincode_serialized = bincode::serialize(&map).unwrap();
let schema_serialized = serialize(&map).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&map, &bincode_deserialized);
prop_assert_eq!(map, schema_deserialized);
}
#[test]
fn test_hash_set_zero_copy(set in proptest::collection::hash_set(any::<StructZeroCopy>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&set).unwrap();
let schema_serialized = serialize(&set).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&set, &bincode_deserialized);
prop_assert_eq!(set, schema_deserialized);
}
#[test]
fn test_hash_set_static(set in proptest::collection::hash_set(any::<StructStatic>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&set).unwrap();
let schema_serialized = serialize(&set).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&set, &bincode_deserialized);
prop_assert_eq!(set, schema_deserialized);
}
#[test]
fn test_hash_set_non_static(set in proptest::collection::hash_set(any::<StructNonStatic>(), 0..=16)) {
let bincode_serialized = bincode::serialize(&set).unwrap();
let schema_serialized = serialize(&set).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&set, &bincode_deserialized);
prop_assert_eq!(set, schema_deserialized);
}
#[test]
fn test_sequences_with_hasher(data in proptest::collection::hash_map(any::<String>(), any::<HashSet<u32>>(), 0..16)) {
#[derive(Default)]
struct SumHasher(u64);
impl BuildHasher for SumHasher {
type Hasher = Self;
fn build_hasher(&self) -> Self::Hasher {
Self(0)
}
}
impl Hasher for SumHasher {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
self.0 += bytes.iter().map(|b| *b as u64).sum::<u64>();
}
}
type TestMap = HashMap<String, HashSet<u32, SumHasher>, SumHasher>;
let test_data: TestMap = data.into_iter().map(|(k, v)| (k, HashSet::from_iter(v.into_iter()))).collect();
let wincode_serialized = serialize(&test_data).unwrap();
let bincode_serialized = bincode::serialize(&test_data).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: TestMap = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: TestMap = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&test_data, &wincode_deserialized);
prop_assert_eq!(wincode_deserialized, bincode_deserialized);
type TestMapSeq = containers::FromIntoIterator<TestMap, BincodeLen>;
let test_seq_serialized = TestMapSeq::serialize(&test_data).unwrap();
assert_eq!(test_seq_serialized, wincode_serialized);
let test_seq_deserialized = TestMapSeq::deserialize(&test_seq_serialized).unwrap();
prop_assert_eq!(&test_data, &test_seq_deserialized);
type RegularMap = HashMap<String, HashSet<u32>>;
let regular_deserialized: RegularMap = deserialize(&wincode_serialized).unwrap();
let regular_serialized = serialize(®ular_deserialized).unwrap();
let test_deserialized: TestMap = deserialize(®ular_serialized).unwrap();
prop_assert_eq!(test_data, test_deserialized);
type RegularMapSeq = containers::FromIntoIterator<RegularMap, BincodeLen>;
let regular_seq_serialized = RegularMapSeq::serialize(®ular_deserialized).unwrap();
assert_eq!(regular_serialized, regular_seq_serialized);
let regular_seq_deserialized = RegularMapSeq::deserialize(®ular_seq_serialized).unwrap();
prop_assert_eq!(®ular_deserialized, ®ular_seq_deserialized);
}
#[test]
fn test_btree_map_zero_copy(map in proptest::collection::btree_map(any::<u8>(), any::<StructZeroCopy>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&map).unwrap();
let schema_serialized = serialize(&map).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&map, &bincode_deserialized);
prop_assert_eq!(map, schema_deserialized);
}
#[test]
fn test_btree_map_static(map in proptest::collection::btree_map(any::<u64>(), any::<StructStatic>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&map).unwrap();
let schema_serialized = serialize(&map).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&map, &bincode_deserialized);
prop_assert_eq!(map, schema_deserialized);
}
#[test]
fn test_btree_map_non_static(map in proptest::collection::btree_map(any::<u64>(), any::<StructNonStatic>(), 0..=16)) {
let bincode_serialized = bincode::serialize(&map).unwrap();
let schema_serialized = serialize(&map).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&map, &bincode_deserialized);
prop_assert_eq!(map, schema_deserialized);
}
#[test]
fn test_btree_set_zero_copy(set in proptest::collection::btree_set(any::<StructZeroCopy>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&set).unwrap();
let schema_serialized = serialize(&set).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&set, &bincode_deserialized);
prop_assert_eq!(set, schema_deserialized);
}
#[test]
fn test_btree_set_static(set in proptest::collection::btree_set(any::<StructStatic>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&set).unwrap();
let schema_serialized = serialize(&set).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&set, &bincode_deserialized);
prop_assert_eq!(set, schema_deserialized);
}
#[test]
fn test_btree_set_non_static(map in proptest::collection::btree_set(any::<StructNonStatic>(), 0..=16)) {
let bincode_serialized = bincode::serialize(&map).unwrap();
let schema_serialized = serialize(&map).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&map, &bincode_deserialized);
prop_assert_eq!(map, schema_deserialized);
}
#[test]
fn test_binary_heap_zero_copy(heap in proptest::collection::binary_heap(any::<StructZeroCopy>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&heap).unwrap();
let schema_serialized = serialize(&heap).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: BinaryHeap<StructZeroCopy> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: BinaryHeap<StructZeroCopy> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(heap.as_slice(), bincode_deserialized.as_slice());
prop_assert_eq!(heap.as_slice(), schema_deserialized.as_slice());
}
#[test]
fn test_binary_heap_static(heap in proptest::collection::binary_heap(any::<StructStatic>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&heap).unwrap();
let schema_serialized = serialize(&heap).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: BinaryHeap<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: BinaryHeap<StructStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(heap.as_slice(), bincode_deserialized.as_slice());
prop_assert_eq!(heap.as_slice(), schema_deserialized.as_slice());
}
#[test]
fn test_binary_heap_non_static(heap in proptest::collection::binary_heap(any::<StructNonStatic>(), 0..=16)) {
let bincode_serialized = bincode::serialize(&heap).unwrap();
let schema_serialized = serialize(&heap).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: BinaryHeap<StructNonStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: BinaryHeap<StructNonStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(heap.as_slice(), bincode_deserialized.as_slice());
prop_assert_eq!(heap.as_slice(), schema_deserialized.as_slice());
}
#[test]
fn test_linked_list_zero_copy(list in proptest::collection::linked_list(any::<StructZeroCopy>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&list).unwrap();
let schema_serialized = serialize(&list).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&list, &bincode_deserialized);
prop_assert_eq!(list, schema_deserialized);
}
#[test]
fn test_linked_list_static(list in proptest::collection::linked_list(any::<StructStatic>(), 0..=100)) {
let bincode_serialized = bincode::serialize(&list).unwrap();
let schema_serialized = serialize(&list).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&list, &bincode_deserialized);
prop_assert_eq!(list, schema_deserialized);
}
#[test]
fn test_linked_list_non_static(list in proptest::collection::linked_list(any::<StructNonStatic>(), 0..=16)) {
let bincode_serialized = bincode::serialize(&list).unwrap();
let schema_serialized = serialize(&list).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&list, &bincode_deserialized);
prop_assert_eq!(list, schema_deserialized);
}
#[test]
fn test_array_bytes(array in any::<[u8; 32]>()) {
let bincode_serialized = bincode::serialize(&array).unwrap();
let schema_serialized = serialize(&array).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: [u8; 32] = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: [u8; 32] = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&array, &bincode_deserialized);
prop_assert_eq!(array, schema_deserialized);
}
#[test]
fn test_array_static(array in any::<[u64; 32]>()) {
let bincode_serialized = bincode::serialize(&array).unwrap();
type Target = [u64; 32];
let schema_serialized = Target::serialize(&array).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Target = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&array, &bincode_deserialized);
prop_assert_eq!(array, schema_deserialized);
}
#[test]
fn test_array_non_static(array in any::<[StructNonStatic; 16]>()) {
let bincode_serialized = bincode::serialize(&array).unwrap();
type Target = [StructNonStatic; 16];
let schema_serialized = Target::serialize(&array).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Target = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&array, &bincode_deserialized);
prop_assert_eq!(array, schema_deserialized);
}
#[test]
fn test_option(option in proptest::option::of(any::<StructStatic>())) {
let bincode_serialized = bincode::serialize(&option).unwrap();
let schema_serialized = serialize(&option).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Option<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Option<StructStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&option, &bincode_deserialized);
prop_assert_eq!(&option, &schema_deserialized);
}
#[test]
fn test_option_container(option in proptest::option::of(any::<[u8; 32]>())) {
let bincode_serialized = bincode::serialize(&option).unwrap();
type Target = Option<[u8; 32]>;
let schema_serialized = Target::serialize(&option).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Option<[u8; 32]> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Option<[u8; 32]> = Target::deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&option, &bincode_deserialized);
prop_assert_eq!(&option, &schema_deserialized);
}
#[test]
fn test_bool(val in any::<bool>()) {
let bincode_serialized = bincode::serialize(&val).unwrap();
let schema_serialized = serialize(&val).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: bool = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: bool = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(val, bincode_deserialized);
prop_assert_eq!(val, schema_deserialized);
}
#[test]
fn test_bool_invalid_bit_pattern(val in 2u8..=255) {
let bincode_deserialized: Result<bool,_> = bincode::deserialize(&[val]);
let schema_deserialized: Result<bool,_> = deserialize(&[val]);
prop_assert!(bincode_deserialized.is_err());
prop_assert!(schema_deserialized.is_err());
}
#[test]
fn test_box(s in any::<StructStatic>()) {
let data = Box::new(s);
let bincode_serialized = bincode::serialize(&data).unwrap();
let schema_serialized = serialize(&data).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Box<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Box<StructStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&data, &bincode_deserialized);
prop_assert_eq!(&data, &schema_deserialized);
}
#[test]
fn test_rc(s in any::<StructStatic>()) {
let data = Rc::new(s);
let bincode_serialized = bincode::serialize(&data).unwrap();
let schema_serialized = serialize(&data).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Rc<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Rc<StructStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&data, &bincode_deserialized);
prop_assert_eq!(&data, &schema_deserialized);
}
#[test]
fn test_arc(s in any::<StructStatic>()) {
let data = Arc::new(s);
let bincode_serialized = bincode::serialize(&data).unwrap();
let schema_serialized = serialize(&data).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Arc<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Arc<StructStatic> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&data, &bincode_deserialized);
prop_assert_eq!(&data, &schema_deserialized);
}
#[test]
fn test_boxed_slice_zero_copy(vec in proptest::collection::vec(any::<StructZeroCopy>(), 0..=100)) {
let data = vec.into_boxed_slice();
let bincode_serialized = bincode::serialize(&data).unwrap();
let schema_serialized = serialize(&data).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Box<[StructZeroCopy]> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Box<[StructZeroCopy]> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&data, &bincode_deserialized);
prop_assert_eq!(&data, &schema_deserialized);
}
#[test]
fn test_boxed_slice_static(vec in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
let data = vec.into_boxed_slice();
let bincode_serialized = bincode::serialize(&data).unwrap();
let schema_serialized = serialize(&data).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Box<[StructStatic]> = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Box<[StructStatic]> = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&data, &bincode_deserialized);
prop_assert_eq!(&data, &schema_deserialized);
}
#[test]
fn test_boxed_slice_non_static(vec in proptest::collection::vec(any::<StructNonStatic>(), 0..=16)) {
let data = vec.into_boxed_slice();
let bincode_serialized = bincode::serialize(&data).unwrap();
type Target = Box<[StructNonStatic]>;
let schema_serialized = serialize(&data).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Target = Target::deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&data, &bincode_deserialized);
prop_assert_eq!(&data, &schema_deserialized);
}
#[test]
fn test_integers(
val in (
any::<u8>(),
any::<i8>(),
any::<u16>(),
any::<i16>(),
any::<u32>(),
any::<i32>(),
any::<usize>(),
any::<isize>(),
any::<u64>(),
any::<i64>(),
any::<u128>(),
any::<i128>()
)
) {
type Target = (u8, i8, u16, i16, u32, i32, usize, isize, u64, i64, u128, i128);
let bincode_serialized = bincode::serialize(&val).unwrap();
let schema_serialized = serialize(&val).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Target = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(val, bincode_deserialized);
prop_assert_eq!(val, schema_deserialized);
}
#[test]
fn test_tuple_zero_copy(
tuple in (
any::<StructZeroCopy>(),
any::<[u8; 32]>(),
)
) {
let bincode_serialized = bincode::serialize(&tuple).unwrap();
let schema_serialized = serialize(&tuple).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&tuple, &bincode_deserialized);
prop_assert_eq!(&tuple, &schema_deserialized);
}
#[test]
fn test_tuple_static(
tuple in (
any::<StructStatic>(),
any::<[u8; 32]>(),
)
) {
let bincode_serialized = bincode::serialize(&tuple).unwrap();
let schema_serialized = serialize(&tuple).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&tuple, &bincode_deserialized);
prop_assert_eq!(&tuple, &schema_deserialized);
}
#[test]
fn test_tuple_non_static(
tuple in (
any::<StructNonStatic>(),
any::<[u8; 32]>(),
proptest::collection::vec(any::<StructStatic>(), 0..=100),
)
) {
let bincode_serialized = bincode::serialize(&tuple).unwrap();
type BincodeTarget = (StructNonStatic, [u8; 32], Vec<StructStatic>);
type Target = (StructNonStatic, [u8; 32], Vec<StructStatic>);
let schema_serialized = Target::serialize(&tuple).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: BincodeTarget = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = Target::deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&tuple, &bincode_deserialized);
prop_assert_eq!(&tuple, &schema_deserialized);
}
#[test]
fn test_str(str in any::<String>()) {
let bincode_serialized = bincode::serialize(&str).unwrap();
let schema_serialized = serialize(&str).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: &str = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: &str = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&str, &bincode_deserialized);
prop_assert_eq!(&str, &schema_deserialized);
let bincode_deserialized: String = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: String = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&str, &bincode_deserialized);
prop_assert_eq!(&str, &schema_deserialized);
}
#[test]
fn test_struct_zero_copy(val in any::<StructZeroCopy>()) {
let bincode_serialized = bincode::serialize(&val).unwrap();
let schema_serialized = serialize(&val).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&val, &bincode_deserialized);
prop_assert_eq!(&val, &schema_deserialized);
}
#[test]
fn test_struct_static(val in any::<StructStatic>()) {
let bincode_serialized = bincode::serialize(&val).unwrap();
let schema_serialized = serialize(&val).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&val, &bincode_deserialized);
prop_assert_eq!(&val, &schema_deserialized);
}
#[test]
fn test_struct_non_static(val in any::<StructNonStatic>()) {
let bincode_serialized = bincode::serialize(&val).unwrap();
let schema_serialized = serialize(&val).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(&val, &bincode_deserialized);
prop_assert_eq!(&val, &schema_deserialized);
}
#[test]
fn test_floats(
val in (
any::<f32>(),
any::<f64>(),
)
) {
let bincode_serialized = bincode::serialize(&val).unwrap();
let schema_serialized = serialize(&val).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: (f32, f64) = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: (f32, f64) = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(val, bincode_deserialized);
prop_assert_eq!(val, schema_deserialized);
}
}
#[test]
fn test_struct_zero_copy_refs() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
#[repr(C)]
struct Zc {
a: u8,
b: [u8; 64],
c: i8,
d: [i8; 64],
}
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
#[wincode(internal)]
#[repr(C)]
struct ZcRefs<'a> {
a: &'a u8,
b: &'a [u8; 64],
c: &'a i8,
d: &'a [i8; 64],
}
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
#[wincode(internal)]
#[repr(transparent)]
struct ZcWrapper<'a> {
data: &'a Zc,
}
impl<'a> From<&'a ZcRefs<'a>> for Zc {
fn from(value: &'a ZcRefs<'a>) -> Self {
Self {
a: *value.a,
b: *value.b,
c: *value.c,
d: *value.d,
}
}
}
proptest!(proptest_cfg(), |(data in any::<Zc>())| {
let serialized = serialize(&data).unwrap();
let deserialized = Zc::deserialize(&serialized).unwrap();
assert_eq!(data, deserialized);
let serialized_ref = serialize(&ZcRefs { a: &data.a, b: &data.b, c: &data.c, d: &data.d }).unwrap();
assert_eq!(serialized_ref, serialized);
let deserialized_ref = ZcRefs::deserialize(&serialized_ref).unwrap();
assert_eq!(data, (&deserialized_ref).into());
let serialized_wrapper = serialize(&ZcWrapper { data: &data }).unwrap();
assert_eq!(serialized_wrapper, serialized);
let deserialized_wrapper = ZcWrapper::deserialize(&serialized_wrapper).unwrap();
assert_eq!(data, *deserialized_wrapper.data);
});
}
#[test]
fn test_zero_copy_ref_with_integer_types() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
#[wincode(internal)]
struct ZcRef<'a> {
x: &'a StructZeroCopy,
}
proptest!(proptest_cfg(), |(data in any::<StructZeroCopy>())| {
let serialized = serialize_aligned(&data).unwrap();
let deserialized: ZcRef<'_> = deserialize(&serialized).unwrap();
assert_eq!(data, *deserialized.x);
});
}
#[test]
fn test_zero_copy_enum_with_integer_types() {
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
#[wincode(tag_encoding = "u128")]
enum Enum {
A,
B(StructZeroCopy),
}
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
#[wincode(internal)]
#[wincode(tag_encoding = "u128")]
enum EnumRef<'a> {
A,
B(&'a StructZeroCopy),
}
proptest!(proptest_cfg(), |(data in any::<Enum>())| {
let serialized = serialize_aligned(&data).unwrap();
let deserialized: EnumRef<'_> = deserialize(&serialized).unwrap();
match data {
Enum::A => prop_assert!(matches!(deserialized, EnumRef::A)),
Enum::B(x) => prop_assert!(matches!(deserialized, EnumRef::B(y) if &x == y)),
}
});
}
#[test]
fn test_empty_struct() {
#[derive(
Debug,
SchemaWrite,
SchemaRead,
Default,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
)]
#[wincode(internal)]
struct EmptyStruct {}
let empty = EmptyStruct::default();
let bincode_serialized = bincode::serialize(&empty).unwrap();
let schema_serialized = serialize(&empty).unwrap();
assert_eq!(bincode_serialized, schema_serialized);
assert_eq!(bincode_serialized.len(), 0);
let bincode_deserialized: EmptyStruct = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: EmptyStruct = deserialize(&schema_serialized).unwrap();
assert_eq!(empty, bincode_deserialized);
assert_eq!(empty, schema_deserialized);
}
#[test]
fn test_pod_zero_copy() {
#[derive(Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy)]
#[repr(transparent)]
struct Address([u8; 64]);
pod_wrapper! {
unsafe struct PodAddress(Address);
}
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
#[repr(C)]
struct MyStruct {
#[wincode(with = "PodAddress")]
address: Address,
}
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
#[wincode(internal)]
struct MyStructRef<'a> {
inner: &'a MyStruct,
}
proptest!(proptest_cfg(), |(data in any::<MyStruct>())| {
let serialized = serialize(&data).unwrap();
let deserialized = MyStruct::deserialize(&serialized).unwrap();
assert_eq!(data, deserialized);
let serialized_ref = serialize(&MyStructRef { inner: &data }).unwrap();
assert_eq!(serialized_ref, serialized);
let deserialized_ref = MyStructRef::deserialize(&serialized_ref).unwrap();
assert_eq!(data, *deserialized_ref.inner);
});
}
#[test]
fn test_pod_zero_copy_explicit_ref() {
#[derive(Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy)]
#[repr(transparent)]
struct Address([u8; 64]);
pod_wrapper! {
unsafe struct PodAddress(Address);
}
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
#[wincode(internal)]
struct MyStructRef<'a> {
#[wincode(with = "&'a PodAddress")]
address: &'a Address,
}
#[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
#[wincode(internal)]
struct MyStruct {
#[wincode(with = "PodAddress")]
address: Address,
}
proptest!(proptest_cfg(), |(data in any::<MyStruct>())| {
let serialized = serialize(&data).unwrap();
let deserialized = MyStruct::deserialize(&serialized).unwrap();
assert_eq!(data, deserialized);
let serialized_ref = serialize(&MyStructRef { address: &data.address }).unwrap();
assert_eq!(serialized_ref, serialized);
let deserialized_ref = MyStructRef::deserialize(&serialized_ref).unwrap();
assert_eq!(data.address, *deserialized_ref.address);
});
}
#[test]
fn test_result_basic() {
proptest!(proptest_cfg(), |(value: Result<u64, String>)| {
let wincode_serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Result<u64, String> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: Result<u64, String> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&value, &wincode_deserialized);
prop_assert_eq!(wincode_deserialized, bincode_deserialized);
});
}
#[test]
fn test_result_bincode_equivalence() {
use serde::{Deserialize, Serialize};
#[derive(
Serialize,
Deserialize,
Debug,
PartialEq,
Clone,
proptest_derive::Arbitrary,
SchemaWrite,
SchemaRead,
)]
#[wincode(internal)]
enum Error {
NotFound,
InvalidInput(String),
Other(u32),
}
proptest!(proptest_cfg(), |(value: Result<Vec<u8>, Error>)| {
let wincode_serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Result<Vec<u8>, Error> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: Result<Vec<u8>, Error> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&value, &wincode_deserialized);
prop_assert_eq!(wincode_deserialized, bincode_deserialized);
});
}
#[test]
fn test_result_nested() {
proptest!(proptest_cfg(), |(value: Result<Result<u64, String>, u32>)| {
let wincode_serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Result<Result<u64, String>, u32> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: Result<Result<u64, String>, u32> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&value, &wincode_deserialized);
prop_assert_eq!(wincode_deserialized, bincode_deserialized);
});
}
#[test]
fn test_result_with_complex_types() {
use std::collections::HashMap;
proptest!(proptest_cfg(), |(value: Result<HashMap<String, Vec<u32>>, bool>)| {
let wincode_serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Result<HashMap<String, Vec<u32>>, bool> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: Result<HashMap<String, Vec<u32>>, bool> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&value, &wincode_deserialized);
prop_assert_eq!(wincode_deserialized, bincode_deserialized);
});
}
#[test]
fn test_result_type_meta_static() {
assert!(matches!(
<Result<u64, u64> as SchemaRead<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 12,
zero_copy: false
}
));
proptest!(proptest_cfg(), |(value: Result<u64, u64>)| {
let wincode_serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Result<u64, u64> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: Result<u64, u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&value, &wincode_deserialized);
prop_assert_eq!(wincode_deserialized, bincode_deserialized);
});
}
#[test]
fn test_result_type_meta_dynamic() {
assert!(matches!(
<Result<u64, String> as SchemaRead<DefaultConfig>>::TYPE_META,
TypeMeta::Dynamic
));
proptest!(proptest_cfg(), |(value: Result<u64, String>)| {
let wincode_serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Result<u64, String> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: Result<u64, String> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&value, &wincode_deserialized);
prop_assert_eq!(wincode_deserialized, bincode_deserialized);
});
}
#[test]
fn test_result_type_meta_different_sizes() {
assert!(matches!(
<Result<u64, u32> as SchemaRead<DefaultConfig>>::TYPE_META,
TypeMeta::Dynamic
));
proptest!(proptest_cfg(), |(value: Result<u64, u32>)| {
let wincode_serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Result<u64, u32> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: Result<u64, u32> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&value, &wincode_deserialized);
prop_assert_eq!(wincode_deserialized, bincode_deserialized);
});
}
struct BufAligned {
buf: *mut u8,
layout: Layout,
}
impl Deref for BufAligned {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { core::slice::from_raw_parts(self.buf as *const u8, self.layout.size()) }
}
}
impl DerefMut for BufAligned {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { core::slice::from_raw_parts_mut(self.buf, self.layout.size()) }
}
}
impl Drop for BufAligned {
fn drop(&mut self) {
use alloc::alloc::dealloc;
unsafe { dealloc(self.buf, self.layout) }
}
}
fn serialize_aligned<T>(src: &T) -> WriteResult<BufAligned>
where
T: SchemaWrite<DefaultConfig, Src = T>,
{
use alloc::alloc::alloc;
let size = T::size_of(src)?;
let layout = Layout::from_size_align(size, align_of::<T>()).unwrap();
let mem = unsafe { alloc(layout) };
if mem.is_null() {
return Err(crate::WriteError::Custom("could not allocate"));
}
let mut buf = BufAligned { buf: mem, layout };
crate::serialize_into(buf.deref_mut(), src)?;
Ok(buf)
}
#[test]
fn test_zero_copy_mut_roundrip() {
proptest!(proptest_cfg(), |(data: StructZeroCopy, data_rand: StructZeroCopy)| {
let mut serialized = serialize_aligned(&data).unwrap();
let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
prop_assert_eq!(deserialized, data);
{
let ref_mut = StructZeroCopy::from_bytes_mut(&mut serialized).unwrap();
*ref_mut = data_rand;
}
let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
prop_assert_eq!(deserialized, data_rand);
});
}
#[test]
fn test_deserialize_mut_roundrip() {
proptest!(proptest_cfg(), |(data: StructZeroCopy, data_rand: StructZeroCopy)| {
let mut serialized = serialize_aligned(&data).unwrap();
let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
prop_assert_eq!(deserialized, data);
{
let ref_mut: &mut StructZeroCopy = deserialize_mut(&mut serialized).unwrap();
*ref_mut = data_rand;
}
let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
prop_assert_eq!(deserialized, data_rand);
});
}
#[test]
fn test_zero_copy_deserialize_ref() {
proptest!(proptest_cfg(), |(data: StructZeroCopy)| {
let serialized = serialize_aligned(&data).unwrap();
let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
prop_assert_eq!(deserialized, data);
let ref_data = StructZeroCopy::from_bytes(&serialized).unwrap();
prop_assert_eq!(ref_data, &data);
});
}
#[test]
fn test_custom_preallocation_size_limit() {
let c = Configuration::default().with_preallocation_size_limit::<64>();
proptest!(proptest_cfg(), |(value in proptest::collection::vec(any::<u8>(), 0..=128))| {
let wincode_serialized = crate::serialize(&value).unwrap();
let wincode_deserialized: Result<Vec<u8>, _> = config::deserialize(&wincode_serialized, c);
if value.len() <= 64 {
prop_assert_eq!(value, wincode_deserialized.unwrap());
} else {
prop_assert!(wincode_deserialized.is_err());
}
});
}
#[test]
fn test_custom_length_encoding() {
let c = Configuration::default().with_length_encoding::<FixIntLen<u32>>();
proptest!(proptest_cfg(), |(value: Vec<u8>)| {
let wincode_serialized = config::serialize(&value, c).unwrap();
let wincode_deserialized: Vec<u8> = config::deserialize(&wincode_serialized, c).unwrap();
let len = value.len();
prop_assert_eq!(len, u32::from_le_bytes(wincode_serialized[0..4].try_into().unwrap()) as usize);
prop_assert_eq!(value, wincode_deserialized);
});
}
#[test]
fn test_duration() {
use core::time::Duration;
proptest!(proptest_cfg(), |(val: Duration)| {
let bincode_serialized = bincode::serialize(&val).unwrap();
let schema_serialized = serialize(&val).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Duration = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Duration = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(val, bincode_deserialized);
prop_assert_eq!(val, schema_deserialized);
});
}
#[test]
fn test_ipv4_addr() {
proptest!(proptest_cfg(), |(addr: Ipv4Addr)| {
let bincode_serialized = bincode::serialize(&addr).unwrap();
let schema_serialized = serialize(&addr).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Ipv4Addr = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Ipv4Addr = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(addr, bincode_deserialized);
prop_assert_eq!(addr, schema_deserialized);
});
}
#[test]
fn test_ipv6_addr() {
proptest!(proptest_cfg(), |(addr: Ipv6Addr)| {
let bincode_serialized = bincode::serialize(&addr).unwrap();
let schema_serialized = serialize(&addr).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: Ipv6Addr = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: Ipv6Addr = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(addr, bincode_deserialized);
prop_assert_eq!(addr, schema_deserialized);
});
}
#[test]
fn test_ip_addr() {
proptest!(proptest_cfg(), |(addr: IpAddr)| {
let bincode_serialized = bincode::serialize(&addr).unwrap();
let schema_serialized = serialize(&addr).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: IpAddr = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: IpAddr = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(addr, bincode_deserialized);
prop_assert_eq!(addr, schema_deserialized);
});
}
#[test]
fn test_socket_addr_v4() {
proptest!(proptest_cfg(), |(addr: SocketAddrV4)| {
let bincode_serialized = bincode::serialize(&addr).unwrap();
let schema_serialized = serialize(&addr).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: SocketAddrV4 = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: SocketAddrV4 = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(addr, bincode_deserialized);
prop_assert_eq!(addr, schema_deserialized);
});
}
#[test]
fn test_socket_addr_v6() {
proptest!(proptest_cfg(), |(addr: SocketAddrV6)| {
let bincode_serialized = bincode::serialize(&addr).unwrap();
let schema_serialized = serialize(&addr).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: SocketAddrV6 = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: SocketAddrV6 = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(bincode_deserialized, schema_deserialized);
});
}
#[test]
fn test_socket_addr() {
proptest!(proptest_cfg(), |(addr: SocketAddr)| {
let bincode_serialized = bincode::serialize(&addr).unwrap();
let schema_serialized = serialize(&addr).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: SocketAddr = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: SocketAddr = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(bincode_deserialized, schema_deserialized);
});
}
#[test]
#[cfg(feature = "std")]
fn test_system_time() {
use std::time::{Duration, SystemTime, UNIX_EPOCH};
const MAX_SECS: u64 = i64::MAX as u64 - 1;
proptest!(proptest_cfg(), |(secs in 0u64..=MAX_SECS, nanos in 0u32..1_000_000_000u32)| {
let time = UNIX_EPOCH + Duration::new(secs, nanos);
let bincode_serialized = bincode::serialize(&time).unwrap();
let schema_serialized = serialize(&time).unwrap();
prop_assert_eq!(&bincode_serialized, &schema_serialized);
let bincode_deserialized: SystemTime = bincode::deserialize(&bincode_serialized).unwrap();
let schema_deserialized: SystemTime = deserialize(&schema_serialized).unwrap();
prop_assert_eq!(time, bincode_deserialized);
prop_assert_eq!(time, schema_deserialized);
});
}
#[test]
#[cfg(feature = "std")]
fn test_system_time_before_epoch_errors() {
use std::time::{Duration, UNIX_EPOCH};
let before_epoch = UNIX_EPOCH.checked_sub(Duration::from_secs(1)).unwrap();
assert!(serialize(&before_epoch).is_err());
}
#[test]
fn test_deserialize_exact_accepts_exact_input() {
let bytes = serialize(&123u64).unwrap();
let value: u64 = deserialize_exact(&bytes).unwrap();
assert_eq!(value, 123);
}
#[test]
fn test_deserialize_exact_rejects_trailing_bytes() {
let mut bytes = serialize(&123u64).unwrap();
bytes.push(0xAA);
let err = deserialize_exact::<u64>(&bytes).unwrap_err();
assert!(matches!(err, error::ReadError::TrailingBytes));
}
#[test]
fn test_config_deserialize_exact_rejects_trailing_bytes() {
let config = Configuration::default();
let mut bytes = config::serialize(&123u64, config).unwrap();
bytes.push(0xAA);
let err = config::deserialize_exact::<u64, _>(&bytes, config).unwrap_err();
assert!(matches!(err, error::ReadError::TrailingBytes));
}
#[test]
#[cfg(feature = "std")]
fn test_system_time_overflow_errors() {
use {crate::serialize_into, std::time::SystemTime};
let mut bytes = Vec::with_capacity(size_of::<u64>() + size_of::<u32>());
serialize_into(&mut bytes, &u64::MAX).unwrap();
serialize_into(&mut bytes, &0u32).unwrap();
let result: ReadResult<SystemTime> = deserialize(&bytes);
assert!(result.is_err());
}
#[test]
fn test_nonzero_types() {
proptest!(proptest_cfg(), |(
nz_u8: NonZeroU8,
nz_u16: NonZeroU16,
nz_u32: NonZeroU32,
nz_u64: NonZeroU64,
nz_u128: NonZeroU128,
nz_usize: NonZeroUsize,
nz_i8: NonZeroI8,
nz_i16: NonZeroI16,
nz_i32: NonZeroI32,
nz_i64: NonZeroI64,
nz_i128: NonZeroI128,
nz_isize: NonZeroIsize,
)| {
let ser = serialize(&nz_u8).unwrap();
let de: NonZeroU8 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_u8, de);
let ser = serialize(&nz_u16).unwrap();
let de: NonZeroU16 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_u16, de);
let ser = serialize(&nz_u32).unwrap();
let de: NonZeroU32 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_u32, de);
let ser = serialize(&nz_u64).unwrap();
let de: NonZeroU64 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_u64, de);
let ser = serialize(&nz_u128).unwrap();
let de: NonZeroU128 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_u128, de);
let ser = serialize(&nz_usize).unwrap();
let de: NonZeroUsize = deserialize(&ser).unwrap();
prop_assert_eq!(nz_usize, de);
let ser = serialize(&nz_i8).unwrap();
let de: NonZeroI8 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_i8, de);
let ser = serialize(&nz_i16).unwrap();
let de: NonZeroI16 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_i16, de);
let ser = serialize(&nz_i32).unwrap();
let de: NonZeroI32 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_i32, de);
let ser = serialize(&nz_i64).unwrap();
let de: NonZeroI64 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_i64, de);
let ser = serialize(&nz_i128).unwrap();
let de: NonZeroI128 = deserialize(&ser).unwrap();
prop_assert_eq!(nz_i128, de);
let ser = serialize(&nz_isize).unwrap();
let de: NonZeroIsize = deserialize(&ser).unwrap();
prop_assert_eq!(nz_isize, de);
});
}
#[test]
fn test_nonzero_invalid_zero_value() {
let zero_bytes = serialize(&0u32).unwrap();
let result: ReadResult<NonZeroU32> = deserialize(&zero_bytes);
assert!(
result.is_err(),
"Deserializing zero should fail for NonZeroU32"
);
let zero_bytes = serialize(&0u64).unwrap();
let result: ReadResult<NonZeroU64> = deserialize(&zero_bytes);
assert!(
result.is_err(),
"Deserializing zero should fail for NonZeroU64"
);
}
#[test]
fn test_bound_included_u64() {
proptest!(proptest_cfg(), |(value in any::<u64>())| {
let bound = Bound::Included(value);
let serialized = serialize(&bound).unwrap();
let deserialized: Bound<u64> = deserialize(&serialized).unwrap();
prop_assert_eq!(&bound, &deserialized);
});
}
#[test]
fn test_bound_excluded_u64() {
proptest!(proptest_cfg(), |(value in any::<u64>())| {
let bound = Bound::Excluded(value);
let serialized = serialize(&bound).unwrap();
let deserialized: Bound<u64> = deserialize(&serialized).unwrap();
prop_assert_eq!(&bound, &deserialized);
});
}
#[test]
fn test_bound_included_string() {
proptest!(proptest_cfg(), |(value in any::<String>())| {
let bound = Bound::Included(value);
let serialized = serialize(&bound).unwrap();
let deserialized: Bound<String> = deserialize(&serialized).unwrap();
prop_assert_eq!(&bound, &deserialized);
});
}
#[test]
fn test_bound_excluded_string() {
proptest!(proptest_cfg(), |(value in any::<String>())| {
let bound = Bound::Excluded(value);
let serialized = serialize(&bound).unwrap();
let deserialized: Bound<String> = deserialize(&serialized).unwrap();
prop_assert_eq!(&bound, &deserialized);
});
}
#[test]
fn test_bound_included_bincode_equivalence() {
proptest!(proptest_cfg(), |(value in any::<u64>())| {
let bound = Bound::Included(value);
let wincode_serialized = serialize(&bound).unwrap();
let bincode_serialized = bincode::serialize(&bound).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Bound<u64> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: Bound<u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&bound, &wincode_deserialized);
prop_assert_eq!(&wincode_deserialized, &bincode_deserialized);
});
}
#[test]
fn test_bound_excluded_bincode_equivalence() {
proptest!(proptest_cfg(), |(value in any::<u64>())| {
let bound = Bound::Excluded(value);
let wincode_serialized = serialize(&bound).unwrap();
let bincode_serialized = bincode::serialize(&bound).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Bound<u64> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: Bound<u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&bound, &wincode_deserialized);
prop_assert_eq!(&wincode_deserialized, &bincode_deserialized);
});
}
#[test]
fn test_range_u64() {
proptest!(proptest_cfg(), |(start in any::<u64>(), end in any::<u64>())| {
let range = Range { start, end };
let serialized = serialize(&range).unwrap();
let deserialized: Range<u64> = deserialize(&serialized).unwrap();
prop_assert_eq!(range.start, deserialized.start);
prop_assert_eq!(range.end, deserialized.end);
});
}
#[test]
fn test_range_string() {
proptest!(proptest_cfg(), |(start in any::<String>(), end in any::<String>())| {
let range = Range { start, end };
let serialized = serialize(&range).unwrap();
let deserialized: Range<String> = deserialize(&serialized).unwrap();
prop_assert_eq!(&range.start, &deserialized.start);
prop_assert_eq!(&range.end, &deserialized.end);
});
}
#[test]
fn test_range_bincode_equivalence() {
proptest!(proptest_cfg(), |(start in any::<u64>(), end in any::<u64>())| {
let range = Range { start, end };
let wincode_serialized = serialize(&range).unwrap();
let bincode_serialized = bincode::serialize(&range).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: Range<u64> = deserialize(&wincode_serialized).unwrap(); let bincode_deserialized: Range<u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(range.start, wincode_deserialized.start);
prop_assert_eq!(range.end, wincode_deserialized.end);
prop_assert_eq!(wincode_deserialized.start, bincode_deserialized.start);
prop_assert_eq!(wincode_deserialized.end, bincode_deserialized.end);
});
}
#[test]
fn test_range_inclusive_u64() {
proptest!(proptest_cfg(), |(start in any::<u64>(), end in any::<u64>())| {
let range = RangeInclusive::new(start, end);
let serialized = serialize(&range).unwrap();
let deserialized: RangeInclusive<u64> = deserialize(&serialized).unwrap();
prop_assert_eq!(range.start(), deserialized.start());
prop_assert_eq!(range.end(), deserialized.end());
});
}
#[test]
fn test_range_inclusive_string() {
proptest!(proptest_cfg(), |(start in any::<String>(), end in any::<String>())| {
let range = RangeInclusive::new(start, end );
let serialized = serialize(&range).unwrap();
let deserialized: RangeInclusive<String> = deserialize(&serialized).unwrap();
prop_assert_eq!(&range.start(), &deserialized.start());
prop_assert_eq!(&range.end(), &deserialized.end());
});
}
#[test]
fn test_range_inclusive_bincode_equivalence() {
proptest!(proptest_cfg(), |(start in any::<u64>(), end in any::<u64>())| {
let range = RangeInclusive::new(start, end );
let wincode_serialized = serialize(&range).unwrap();
let bincode_serialized = bincode::serialize(&range).unwrap();
prop_assert_eq!(&wincode_serialized, &bincode_serialized);
let wincode_deserialized: RangeInclusive<u64> = deserialize(&wincode_serialized).unwrap();
let bincode_deserialized: RangeInclusive<u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(range.start(), wincode_deserialized.start());
prop_assert_eq!(range.end(), wincode_deserialized.end());
prop_assert_eq!(wincode_deserialized.start(), bincode_deserialized.start());
prop_assert_eq!(wincode_deserialized.end(), bincode_deserialized.end());
});
}
#[test]
fn test_range_vec_u64() {
proptest!(proptest_cfg(), |(ranges: Vec<Range<u64>>)| {
let serialized = serialize(&ranges).unwrap();
let bincode_serialized = bincode::serialize(&ranges).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: Vec<Range<u64>> = deserialize(&serialized).unwrap();
let bincode_deserialized: Vec<Range<u64>> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(deserialized, bincode_deserialized);
});
}
#[test]
fn test_range_inclusive_vec_u64() {
proptest!(proptest_cfg(), |(ranges: Vec<RangeInclusive<u64>>)| {
let serialized = serialize(&ranges).unwrap();
let bincode_serialized = bincode::serialize(&ranges).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: Vec<RangeInclusive<u64>> = deserialize(&serialized).unwrap();
let bincode_deserialized: Vec<RangeInclusive<u64>> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(deserialized, bincode_deserialized);
});
}
#[test]
fn test_bound_vec_u64() {
proptest!(proptest_cfg(), |(bounds: Vec<Bound<u64>>)| {
let serialized = serialize(&bounds).unwrap();
let bincode_serialized = bincode::serialize(&bounds).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: Vec<Bound<u64>> = deserialize(&serialized).unwrap();
let bincode_deserialized: Vec<Bound<u64>> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(deserialized, bincode_deserialized);
});
}
#[test]
fn test_byte_order_configuration() {
let c = Configuration::default().with_big_endian();
let bincode_c = bincode::DefaultOptions::new()
.with_big_endian()
.with_fixint_encoding();
proptest!(proptest_cfg(), |(value: Vec<u64>)| {
let bincode_serialized = bincode_c.serialize(&value).unwrap();
let serialized = config::serialize(&value, c).unwrap();
prop_assert_eq!(&bincode_serialized, &serialized);
let deserialized: Vec<u64> = config::deserialize(&serialized, c).unwrap();
let len = value.len();
prop_assert_eq!(len, u64::from_be_bytes(serialized[0..8].try_into().unwrap()) as usize);
if !value.is_empty() {
for (i, chunk) in serialized[8..].chunks(8).enumerate() {
let val = u64::from_be_bytes(chunk.try_into().unwrap());
prop_assert_eq!(val, value[i]);
}
}
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_duration_nanos_normalization() {
use core::time::Duration;
proptest!(proptest_cfg(), |(secs in 0u64..u64::MAX/2, nanos in 1_000_000_000u32..=u32::MAX)| {
let mut bytes: Vec<u8> = Vec::with_capacity(size_of::<u64>() + size_of::<u32>());
crate::serialize_into(&mut bytes, &secs).unwrap();
crate::serialize_into(&mut bytes, &nanos).unwrap();
let result: Duration = deserialize(&bytes).unwrap();
let expected = Duration::new(secs, nanos);
prop_assert_eq!(result, expected);
});
}
#[test]
fn test_custom_length_encoding_and_byte_order() {
let c = Configuration::default()
.with_length_encoding::<FixIntLen<u32>>()
.with_big_endian();
proptest!(proptest_cfg(), |(value: Vec<u8>)| {
let serialized = config::serialize(&value, c).unwrap();
let deserialized: Vec<u8> = config::deserialize(&serialized, c).unwrap();
let len = value.len();
prop_assert_eq!(len, u32::from_be_bytes(serialized[0..4].try_into().unwrap()) as usize);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_custom_primitive_length_encoding() {
let c = Configuration::default().with_length_encoding::<u32>();
proptest!(proptest_cfg(), |(value: Vec<u8>)| {
let serialized = config::serialize(&value, c).unwrap();
let deserialized: Vec<u8> = config::deserialize(&serialized, c).unwrap();
let len = value.len();
prop_assert_eq!(len, u32::from_le_bytes(serialized[0..4].try_into().unwrap()) as usize);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_duration_overflow() {
use core::time::Duration;
let mut bytes = Vec::with_capacity(size_of::<u64>() + size_of::<u32>());
crate::serialize_into(&mut bytes, &u64::MAX).unwrap();
crate::serialize_into(&mut bytes, &1_000_000_000u32).unwrap();
let result: error::ReadResult<Duration> = deserialize(&bytes);
assert!(result.is_err());
}
#[test]
fn test_all_integers_with_custom_byte_order() {
let c = Configuration::default().with_big_endian();
let bincode_c = bincode::DefaultOptions::new()
.with_big_endian()
.with_fixint_encoding();
proptest!(proptest_cfg(), |(value: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize))| {
let bincode_serialized = bincode_c.serialize(&value).unwrap();
let serialized = config::serialize(&value, c).unwrap();
prop_assert_eq!(&bincode_serialized, &serialized);
let deserialized: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize) = config::deserialize(&serialized, c).unwrap();
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_all_integers_with_varint() {
let c = Configuration::default().with_varint_encoding();
let bincode_c = bincode::DefaultOptions::new().with_varint_encoding();
proptest!(proptest_cfg(), |(value: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize))| {
let bincode_serialized = bincode_c.serialize(&value).unwrap();
let serialized = config::serialize(&value, c).unwrap();
prop_assert_eq!(&bincode_serialized, &serialized);
prop_assert_eq!(bincode_c.serialized_size(&value).unwrap(), config::serialized_size(&value, c).unwrap());
let deserialized: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize) = config::deserialize(&serialized, c).unwrap();
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_all_integers_with_varint_big_endian() {
let c = Configuration::default()
.with_varint_encoding()
.with_big_endian();
let bincode_c = bincode::DefaultOptions::new()
.with_varint_encoding()
.with_big_endian();
proptest!(proptest_cfg(), |(value: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize))| {
let bincode_serialized = bincode_c.serialize(&value).unwrap();
let serialized = config::serialize(&value, c).unwrap();
prop_assert_eq!(&bincode_serialized, &serialized);
prop_assert_eq!(bincode_c.serialized_size(&value).unwrap(), config::serialized_size(&value, c).unwrap());
let deserialized: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize) = config::deserialize(&serialized, c).unwrap();
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_varint_boundaries() {
let c = Configuration::default().with_varint_encoding();
let bincode_c = bincode::DefaultOptions::new().with_varint_encoding();
fn assert_varint_roundtrip<T, C, O>(val: T, c: C, bincode_c: O)
where
C: Config + Copy,
O: Options + Copy,
T: serde::Serialize
+ for<'de> Deserialize<'de>
+ PartialEq
+ core::fmt::Debug
+ SchemaWrite<C, Src = T>
+ for<'de> SchemaRead<'de, C, Dst = T>,
{
let bincode_serialized = bincode_c.serialize(&val).unwrap();
let serialized = config::serialize(&val, c).unwrap();
assert_eq!(bincode_serialized, serialized);
assert_eq!(
bincode_c.serialized_size(&val).unwrap(),
config::serialized_size(&val, c).unwrap()
);
let deserialized: T = config::deserialize(&serialized, c).unwrap();
assert_eq!(val, deserialized);
}
for val in [0u16, 1, 250, 251, 252, u16::MAX] {
assert_varint_roundtrip(val, c, bincode_c);
}
for val in [
0u32,
1,
250,
251,
252,
u16::MAX as u32,
u16::MAX as u32 + 1,
u32::MAX,
] {
assert_varint_roundtrip(val, c, bincode_c);
}
for val in [
0u64,
1,
250,
251,
252,
u16::MAX as u64,
u16::MAX as u64 + 1,
u32::MAX as u64,
u32::MAX as u64 + 1,
u64::MAX,
] {
assert_varint_roundtrip(val, c, bincode_c);
}
for val in [
0u128,
1,
250,
251,
252,
u16::MAX as u128,
u16::MAX as u128 + 1,
u32::MAX as u128,
u32::MAX as u128 + 1,
u64::MAX as u128,
u64::MAX as u128 + 1,
u128::MAX,
] {
assert_varint_roundtrip(val, c, bincode_c);
}
for val in [0i16, 1, -1, 2, -2, i16::MIN, i16::MAX] {
assert_varint_roundtrip(val, c, bincode_c);
}
for val in [0i32, 1, -1, 2, -2, i32::MIN, i32::MAX] {
assert_varint_roundtrip(val, c, bincode_c);
}
for val in [0i64, 1, -1, 2, -2, i64::MIN, i64::MAX] {
assert_varint_roundtrip(val, c, bincode_c);
}
for val in [0i128, 1, -1, 2, -2, i128::MIN, i128::MAX] {
assert_varint_roundtrip(val, c, bincode_c);
}
}
#[test]
fn test_floats_with_custom_byte_order() {
let c = Configuration::default().with_big_endian();
let bincode_c = bincode::DefaultOptions::new()
.with_big_endian()
.with_fixint_encoding();
proptest!(proptest_cfg(), |(value: (f32, f64))| {
let bincode_serialized = bincode_c.serialize(&value).unwrap();
let serialized = config::serialize(&value, c).unwrap();
prop_assert_eq!(&bincode_serialized, &serialized);
let deserialized: (f32, f64) = config::deserialize(&serialized, c).unwrap();
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_generic_struct() {
#[derive(
SchemaWrite,
SchemaRead,
serde::Serialize,
serde::Deserialize,
Debug,
PartialEq,
Eq,
proptest_derive::Arbitrary,
)]
#[wincode(internal)]
struct GenT<T> {
inner: T,
}
assert_eq!(
<GenT<u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 8,
zero_copy: false
}
);
assert_eq!(
<GenT<String> as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Dynamic,
);
proptest!(proptest_cfg(), |(value: GenT<u64>)| {
let serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: GenT<u64> = deserialize(&serialized).unwrap();
let bincode_deserialized: GenT<u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_generic_struct_two_params() {
#[derive(
SchemaWrite,
SchemaRead,
serde::Serialize,
serde::Deserialize,
Debug,
PartialEq,
Eq,
proptest_derive::Arbitrary,
)]
#[wincode(internal)]
struct GenT<T, U> {
t: T,
u: U,
}
assert_eq!(
<GenT<u64, u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 16,
zero_copy: false
}
);
assert_eq!(
<GenT<String, u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Dynamic,
);
proptest!(proptest_cfg(), |(value: GenT<u64, u64>)| {
let serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: GenT<u64, u64> = deserialize(&serialized).unwrap();
let bincode_deserialized: GenT<u64, u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_generic_struct_repr_transparent() {
#[derive(
SchemaWrite,
SchemaRead,
serde::Serialize,
serde::Deserialize,
Debug,
PartialEq,
Eq,
proptest_derive::Arbitrary,
)]
#[wincode(internal)]
#[repr(transparent)]
struct GenT<T> {
inner: T,
}
assert_eq!(
<GenT<u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: 8,
zero_copy: true
}
);
proptest!(proptest_cfg(), |(value: GenT<u64>)| {
let serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: GenT<u64> = deserialize(&serialized).unwrap();
let bincode_deserialized: GenT<u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_generic_struct_with_existing_bound() {
#[derive(
SchemaWrite,
SchemaRead,
serde::Serialize,
serde::Deserialize,
Debug,
PartialEq,
Eq,
proptest_derive::Arbitrary,
)]
#[wincode(internal)]
#[repr(transparent)]
struct GenT<T: Copy> {
inner: T,
}
proptest!(proptest_cfg(), |(value: GenT<u64>)| {
let serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: GenT<u64> = deserialize(&serialized).unwrap();
let bincode_deserialized: GenT<u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_generic_enum() {
#[derive(
SchemaWrite,
SchemaRead,
serde::Serialize,
serde::Deserialize,
Debug,
PartialEq,
Eq,
proptest_derive::Arbitrary,
)]
#[wincode(internal)]
enum GenT<T> {
A(T),
B(u8),
}
assert_eq!(
<GenT<u8> as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Static {
size: size_of::<u32>() + 1,
zero_copy: false
}
);
assert_eq!(
<GenT<u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
TypeMeta::Dynamic,
);
proptest!(proptest_cfg(), |(value: GenT<u64>)| {
let serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: GenT<u64> = deserialize(&serialized).unwrap();
let bincode_deserialized: GenT<u64> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_recursive_type() {
#[derive(
SchemaWrite, SchemaRead, PartialEq, Debug, serde::Serialize, serde::Deserialize,
)]
#[wincode(internal)]
pub enum Value {
Usize(usize),
List(Vec<Value>),
}
let val = Value::List(vec![Value::Usize(0), Value::List(vec![Value::Usize(1)])]);
let bincode_serialized = bincode::serialize(&val).unwrap();
let serialized = serialize(&val).unwrap();
assert_eq!(&bincode_serialized, &serialized);
let deserialized: Value = deserialize(&serialized).unwrap();
let bincode_deserialized: Value = bincode::deserialize(&bincode_serialized).unwrap();
assert_eq!(&val, &bincode_deserialized);
assert_eq!(val, deserialized);
}
#[test]
fn test_cow_str() {
proptest!(proptest_cfg(), |(value: Cow<str>)| {
let serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: Cow<str> = deserialize(&serialized).unwrap();
let bincode_deserialized: Cow<str> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_cow_bytes() {
proptest!(proptest_cfg(), |(value: Cow<[u8]>)| {
let serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized: Cow<[u8]> = deserialize(&serialized).unwrap();
let bincode_deserialized: Cow<[u8]> = bincode::deserialize(&bincode_serialized).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_cow_bytes_owned() {
proptest!(proptest_cfg(), |(value: Cow<[u8]>)| {
let serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized = <Cow<[u8]> as SchemaRead<DefaultConfig>>
::get(NoBorrowReader::new(&serialized)).unwrap();
let bincode_deserialized: Cow<[u8]> = bincode::deserialize_from(bincode_serialized.as_slice()).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_cow_str_owned() {
proptest!(proptest_cfg(), |(value: Cow<str>)| {
let serialized = serialize(&value).unwrap();
let bincode_serialized = bincode::serialize(&value).unwrap();
prop_assert_eq!(&serialized, &bincode_serialized);
let deserialized = <Cow<str> as SchemaRead<DefaultConfig>>
::get(NoBorrowReader::new(&serialized)).unwrap();
let bincode_deserialized: Cow<str> = bincode::deserialize_from(bincode_serialized.as_slice()).unwrap();
prop_assert_eq!(&deserialized, &bincode_deserialized);
prop_assert_eq!(value, deserialized);
});
}
#[test]
fn test_cow_ctx() {
#[derive(Debug, PartialEq)]
struct MaybeBorrowed<'a> {
len: u8,
data: Cow<'a, [u8]>,
}
unsafe impl<'a, C: ConfigCore> SchemaWrite<C> for MaybeBorrowed<'a> {
type Src = Self;
fn size_of(src: &Self::Src) -> WriteResult<usize> {
Ok(1 + src.data.len())
}
fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
writer.write(&[src.data.len() as u8])?;
writer.write(&src.data)?;
Ok(())
}
}
unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for MaybeBorrowed<'de> {
type Dst = Self;
fn read(
mut reader: impl Reader<'de>,
dst: &mut MaybeUninit<Self::Dst>,
) -> ReadResult<()> {
let len = reader.take_byte()?;
let cow = <Cow<'de, [u8]> as SchemaReadContext<C, _>>::get_with_context(
context::Len(len as usize),
reader,
)?;
dst.write(MaybeBorrowed { len, data: cow });
Ok(())
}
}
proptest!(proptest_cfg(), |(value in proptest::collection::vec(any::<u8>(), 0..=64))| {
let value = MaybeBorrowed {
len: value.len() as u8,
data: Cow::Owned(value),
};
let serialized = serialize(&value).unwrap();
let deserialized = <MaybeBorrowed as SchemaRead<DefaultConfig>>
::get(NoBorrowReader::new(&serialized)).unwrap();
prop_assert!(matches!(deserialized.data, Cow::Owned(_)));
prop_assert_eq!(&value, &deserialized);
let deserialized: MaybeBorrowed = deserialize(&serialized).unwrap();
prop_assert!(matches!(deserialized.data, Cow::Borrowed(_)));
prop_assert_eq!(value, deserialized);
});
}
}