Skip to main content

wincode/schema/
mod.rs

1//! Schema traits.
2//!
3//! # Example
4//!
5//! ```
6//! # #[cfg(all(feature = "alloc", feature = "derive"))] {
7//! # use rand::random;
8//! # use wincode::{Serialize, Deserialize, len::UseIntLen, containers};
9//! # use wincode_derive::{SchemaWrite, SchemaRead};
10//! # use core::{array, mem::size_of};
11//!
12//! # #[derive(Debug, PartialEq, Eq)]
13//! #[repr(transparent)]
14//! #[derive(Clone, Copy)]
15//! struct Signature([u8; 32]);
16//! # #[derive(Debug, PartialEq, Eq)]
17//! #[repr(transparent)]
18//! #[derive(Clone, Copy)]
19//! struct Address([u8; 32]);
20//!
21//! wincode::pod_wrapper! {
22//!     unsafe struct PodSignature(Signature);
23//!     unsafe struct PodAddress(Address);
24//! }
25//!
26//! # #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
27//! struct MyStruct {
28//!     #[wincode(with = "containers::Vec<PodSignature, UseIntLen<u16>>")]
29//!     signature: Vec<Signature>,
30//!     #[wincode(with = "containers::Vec<PodAddress, UseIntLen<u16>>")]
31//!     address: Vec<Address>,
32//! }
33//!
34//! let my_struct = MyStruct {
35//!     signature: (0..10).map(|_| Signature(array::from_fn(|_| random()))).collect(),
36//!     address: (0..10).map(|_| Address(array::from_fn(|_| random()))).collect(),
37//! };
38//! let bytes = MyStruct::serialize(&my_struct).unwrap();
39//! assert_eq!(
40//!     bytes.len(),
41//!     (size_of::<u16>() + my_struct.signature.len() * size_of::<Signature>())
42//!         + (size_of::<u16>() + my_struct.address.len() * size_of::<Address>()),
43//! );
44//! assert_eq!(my_struct, MyStruct::deserialize(&bytes).unwrap());
45//! # }
46//! ```
47use {
48    crate::{
49        config::{self, ConfigCore, DefaultConfig},
50        error::{ReadResult, WriteResult},
51        io::*,
52        len::SeqLen,
53    },
54    core::{borrow::Borrow, mem::MaybeUninit},
55};
56
57pub mod adapter;
58mod compile_fail;
59pub mod containers;
60pub mod context;
61mod external;
62mod impls;
63pub mod int_encoding;
64pub mod tag_encoding;
65
66/// Indicates what kind of assumptions can be made when encoding or decoding a type.
67///
68/// Readers and writers may use this to optimize their behavior.
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum TypeMeta {
71    /// The type has a statically known serialized size.
72    ///
73    /// Specifying this variant can have significant performance benefits, as it can allow
74    /// writers to prefetch larger chunks of memory such that subsequent read/write operations
75    /// in those chunks can be performed at once without intermediate bounds checks.
76    ///
77    /// Specifying this variant incorrectly will almost certainly result in a panic at runtime.
78    ///
79    /// Take care not to specify this on variable length types, like `Vec` or `String`, as their
80    /// serialized size will vary based on their length.
81    Static {
82        /// The static serialized size of the type.
83        size: usize,
84        /// Whether the type is eligible for zero-copy encoding/decoding.
85        ///
86        /// This indicates that the type has no invalid bit patterns, no layout requirements, no endianness
87        /// checks, etc. This is a very strong claim that should be used judiciously.
88        ///
89        /// Specifying this incorrectly may trigger UB.
90        zero_copy: bool,
91    },
92    /// The type has a dynamic size, and no optimizations can be made.
93    Dynamic,
94}
95
96impl TypeMeta {
97    #[inline(always)]
98    pub(crate) const fn size_assert_zero_copy(self) -> usize {
99        match self {
100            TypeMeta::Static {
101                size,
102                zero_copy: true,
103            } => size,
104            _ => panic!("Type is not zero-copy"),
105        }
106    }
107
108    #[cfg(all(test, feature = "std", feature = "derive"))]
109    pub(crate) const fn size_assert_static(self) -> usize {
110        match self {
111            TypeMeta::Static { size, zero_copy: _ } => size,
112            _ => panic!("Type is not static"),
113        }
114    }
115
116    /// Returns this [`TypeMeta`] instance with `zero_copy` masked by `keep_zero_copy`.
117    ///
118    /// For `TypeMeta::Static`, this preserves `size` and computes:
119    /// `zero_copy = zero_copy && keep_zero_copy`.
120    ///
121    /// For `TypeMeta::Dynamic`, this is a no-op.
122    ///
123    /// This method never upgrades a type to zero-copy.
124    /// - `keep_zero_copy(true)` leaves the flag unchanged.
125    /// - `keep_zero_copy(false)` clears the flag.
126    pub const fn keep_zero_copy(self, keep_zero_copy: bool) -> Self {
127        match self {
128            Self::Static { size, zero_copy } => TypeMeta::Static {
129                size,
130                zero_copy: zero_copy && keep_zero_copy,
131            },
132            Self::Dynamic => Self::Dynamic,
133        }
134    }
135
136    /// Combines multiple constituent [`TypeMeta`] values into one aggregate.
137    ///
138    /// Intended for composite types whose constituents are serialized sequentially.
139    ///
140    /// Semantics:
141    /// - If any input is `Dynamic`, returns `Dynamic`.
142    /// - Otherwise returns `Static` with:
143    ///   - `size = sum of all constituent sizes`
144    ///   - `zero_copy = logical AND of all constituent zero_copy flags`
145    ///
146    /// Notes:
147    /// - This function does **not** validate layout/padding; it only combines metadata.
148    /// - For `N = 0`, the result is `TypeMeta::Static { size: 0, zero_copy: true }`.
149    /// - The caller must ensure the summed size is meaningful for the target type.
150    ///
151    /// ```
152    /// use wincode::TypeMeta;
153    ///
154    /// let types = [
155    ///     TypeMeta::Static { size: 1, zero_copy: true },
156    ///     TypeMeta::Static { size: 2, zero_copy: true },
157    ///     TypeMeta::Dynamic,
158    ///     TypeMeta::Static { size: 3, zero_copy: true },
159    /// ];
160    /// assert_eq!(TypeMeta::join_types(types), TypeMeta::Dynamic);
161    /// ```
162    ///
163    /// ```
164    /// use wincode::TypeMeta;
165    ///
166    /// let types = [
167    ///     TypeMeta::Static { size: 1, zero_copy: true },
168    ///     TypeMeta::Static { size: 2, zero_copy: true },
169    ///     TypeMeta::Static { size: 3, zero_copy: true },
170    /// ];
171    /// assert_eq!(TypeMeta::join_types(types), TypeMeta::Static { size: 6, zero_copy: true });
172    /// ```
173    ///
174    /// ```
175    /// use wincode::TypeMeta;
176    ///
177    /// let types = [
178    ///     TypeMeta::Static { size: 1, zero_copy: true },
179    ///     TypeMeta::Static { size: 2, zero_copy: false },
180    ///     TypeMeta::Static { size: 3, zero_copy: true },
181    /// ];
182    /// assert_eq!(TypeMeta::join_types(types), TypeMeta::Static { size: 6, zero_copy: false });
183    /// ```
184    #[expect(clippy::arithmetic_side_effects)]
185    pub const fn join_types<const N: usize>(types: [Self; N]) -> Self {
186        let mut acc_size = 0;
187        let mut all_zero_copy = true;
188        let mut i = 0;
189        while i < N {
190            match types[i] {
191                Self::Dynamic => return Self::Dynamic,
192                Self::Static { size, zero_copy } => {
193                    acc_size += size;
194                    all_zero_copy &= zero_copy;
195                }
196            }
197            i += 1;
198        }
199        Self::Static {
200            size: acc_size,
201            zero_copy: all_zero_copy,
202        }
203    }
204}
205
206/// Types that can be written (serialized) to a [`Writer`].
207///
208/// # Safety
209///
210/// Implementors must adhere to the Safety section of the associated constant
211/// `TYPE_META` (or leave it as the default) and the method `size_of`
212pub unsafe trait SchemaWrite<C: ConfigCore> {
213    type Src: ?Sized;
214
215    /// Metadata about the type's serialization.
216    ///
217    /// # Safety
218    ///
219    /// It is always safe to leave this as the default `TypeMeta::Dynamic`. If
220    /// you set it to `TypeMeta::Static { size, zero_copy }`, you have to ensure
221    /// the following two points:
222    /// - `size` must always correspond to the number of bytes written by
223    ///   `write`. `size_of` must always return `Ok(size)`.
224    /// - If `zero_copy` is `true`, `Src`'s in-memory representation must
225    ///   correspond exactly to the serialized form. There must be no padding in
226    ///   the in-memory representation of `Src`.
227    const TYPE_META: TypeMeta = TypeMeta::Dynamic;
228
229    #[cfg(test)]
230    #[allow(unused_variables)]
231    fn type_meta(config: C) -> TypeMeta {
232        Self::TYPE_META
233    }
234
235    /// Get the serialized size of `Self::Src`.
236    ///
237    /// # Safety
238    ///
239    /// If `Ok(…)` is returned, it must contain the exact number of bytes
240    /// written by the `write` function for this particular object instance.
241    fn size_of(src: &Self::Src) -> WriteResult<usize>;
242
243    /// Write `Self::Src` to `writer`.
244    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()>;
245}
246
247/// Types that can be read (deserialized) from a [`Reader`].
248///
249/// # Safety
250///
251/// Implementors must adhere to the Safety section of the associated constant
252/// `TYPE_META` (or leave it as the default) and the method `read`.
253pub unsafe trait SchemaRead<'de, C: ConfigCore> {
254    type Dst;
255
256    /// Metadata about the type's serialization.
257    ///
258    /// # Safety
259    ///
260    /// It is always safe to leave this as the default `TypeMeta::Dynamic`. If
261    /// you set it to `TypeMeta::Static { size, zero_copy }`, you have to ensure
262    /// the following two points:
263    /// - `size` must always correspond to the number of bytes read by `read`.
264    /// - If `zero_copy` is `true`, `Dst`'s in-memory representation must
265    ///   correspond exactly to the serialized form, and all byte sequences must
266    ///   be valid in-memory representations of `Dst`.
267    const TYPE_META: TypeMeta = TypeMeta::Dynamic;
268
269    #[cfg(test)]
270    #[allow(unused_variables)]
271    fn type_meta(config: C) -> TypeMeta {
272        Self::TYPE_META
273    }
274
275    /// Read into `dst` from `reader`.
276    ///
277    /// # Safety
278    ///
279    /// You must initialize `dst` if **and only if** you return `Ok(())`. In the
280    /// `Err(…)` case, initializing `dst` can lead to memory leaks.
281    ///
282    /// It is permissible to not initialize `dst` if `dst` is an inhabited
283    /// zero-sized type.
284    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()>;
285
286    /// Read `Self::Dst` from `reader` into a new `Self::Dst`.
287    #[inline(always)]
288    fn get(reader: impl Reader<'de>) -> ReadResult<Self::Dst> {
289        let mut value = MaybeUninit::uninit();
290        Self::read(reader, &mut value)?;
291        // SAFETY: `read` must properly initialize the `Self::Dst`.
292        Ok(unsafe { value.assume_init() })
293    }
294}
295
296/// Types that can be read (deserialized) from a [`Reader`] with an additional context parameter.
297///
298/// # Safety
299///
300/// Implementors must adhere to the Safety section of the associated constant
301/// `TYPE_META` (or leave it as the default) and the method `read`.
302pub unsafe trait SchemaReadContext<'de, C: ConfigCore, Ctx> {
303    type Dst;
304
305    /// Metadata about the type's serialization.
306    ///
307    /// # Safety
308    ///
309    /// It is always safe to leave this as the default `TypeMeta::Dynamic`. If
310    /// you set it to `TypeMeta::Static { size, zero_copy }`, you have to ensure
311    /// the following two points:
312    /// - `size` must always correspond to the number of bytes read by `read`.
313    /// - If `zero_copy` is `true`, `Dst`'s in-memory representation must
314    ///   correspond exactly to the serialized form, and all byte sequences must
315    ///   be valid in-memory representations of `Dst`.
316    const TYPE_META: TypeMeta = TypeMeta::Dynamic;
317
318    /// Read into `dst` from `reader` with context.
319    ///
320    /// You must initialize `dst` if **and only if** you return `Ok(())`. In the
321    /// `Err(…)` case, initializing `dst` can lead to memory leaks.
322    ///
323    /// It is permissible to not initialize `dst` if `dst` is an inhabited
324    /// zero-sized type.
325    fn read_with_context(
326        ctx: Ctx,
327        reader: impl Reader<'de>,
328        dst: &mut MaybeUninit<Self::Dst>,
329    ) -> ReadResult<()>;
330
331    /// Read `Self::Dst` from `reader` into a new `Self::Dst` with context.
332    #[inline(always)]
333    fn get_with_context(ctx: Ctx, reader: impl Reader<'de>) -> ReadResult<Self::Dst> {
334        let mut value = MaybeUninit::uninit();
335        Self::read_with_context(ctx, reader, &mut value)?;
336        // SAFETY: `read_with_context` must properly initialize the `Self::Dst`.
337        Ok(unsafe { value.assume_init() })
338    }
339}
340
341/// Marker trait for types that can be deserialized via direct borrows from a [`Reader`]
342/// using the default configuration. See [`config::ZeroCopy`] for configuration
343/// aware methods.
344///
345/// Always prefer using [`config::ZeroCopy`] for your implementations to keep them fully
346/// generic.
347///
348/// # Safety
349///
350/// - The type must not have any invalid bit patterns, no layout requirements, no endianness checks, etc.
351pub unsafe trait ZeroCopy: config::ZeroCopy<DefaultConfig> {
352    /// Get a reference to a type from the given bytes.
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// # #[cfg(all(feature = "alloc", feature = "derive"))] {
358    /// # use wincode::{SchemaWrite, SchemaRead, ZeroCopy};
359    /// # #[derive(Debug, PartialEq, Eq)]
360    /// #[derive(SchemaWrite, SchemaRead)]
361    /// #[repr(C)]
362    /// struct Data {
363    ///     bytes: [u8; 7],
364    ///     the_answer: u8,
365    /// }
366    ///
367    /// let data = Data { bytes: *b"wincode", the_answer: 42 };
368    ///
369    /// let serialized = wincode::serialize(&data).unwrap();
370    /// let data_ref = Data::from_bytes(&serialized).unwrap();
371    ///
372    /// assert_eq!(data_ref, &data);
373    /// # }
374    /// ```
375    #[inline(always)]
376    fn from_bytes<'de>(bytes: &'de [u8]) -> ReadResult<&'de Self>
377    where
378        Self: SchemaRead<'de, DefaultConfig, Dst = Self> + Sized,
379    {
380        <&Self as SchemaRead<'de, DefaultConfig>>::get(bytes)
381    }
382
383    /// Get a mutable reference to a type from the given bytes.
384    ///
385    /// # Examples
386    ///
387    /// ```
388    /// # #[cfg(all(feature = "alloc", feature = "derive"))] {
389    /// # use wincode::{SchemaWrite, SchemaRead, ZeroCopy};
390    /// # #[derive(Debug, PartialEq, Eq)]
391    /// #[derive(SchemaWrite, SchemaRead)]
392    /// #[repr(C)]
393    /// struct Data {
394    ///     bytes: [u8; 7],
395    ///     the_answer: u8,
396    /// }
397    ///
398    /// let data = Data { bytes: [0; 7], the_answer: 0 };
399    ///
400    /// let mut serialized = wincode::serialize(&data).unwrap();
401    /// let data_mut = Data::from_bytes_mut(&mut serialized).unwrap();
402    /// data_mut.bytes = *b"wincode";
403    /// data_mut.the_answer = 42;
404    ///
405    /// let deserialized: Data = wincode::deserialize(&serialized).unwrap();
406    /// assert_eq!(deserialized, Data { bytes: *b"wincode", the_answer: 42 });
407    /// # }
408    /// ```
409    #[inline(always)]
410    fn from_bytes_mut<'de>(bytes: &'de mut [u8]) -> ReadResult<&'de mut Self>
411    where
412        Self: SchemaRead<'de, DefaultConfig, Dst = Self> + Sized,
413    {
414        <&mut Self as SchemaRead<'de, DefaultConfig>>::get(bytes)
415    }
416}
417
418unsafe impl<T> ZeroCopy for T where T: config::ZeroCopy<DefaultConfig> {}
419
420/// A type that can be read (deserialized) from a [`Reader`] without borrowing from it.
421pub trait SchemaReadOwned<C: ConfigCore>: for<'de> SchemaRead<'de, C> {}
422impl<T, C: ConfigCore> SchemaReadOwned<C> for T where T: for<'de> SchemaRead<'de, C> {}
423
424#[inline(always)]
425#[allow(clippy::arithmetic_side_effects)]
426fn size_of_elem_iter<T, Len, C>(
427    value: impl ExactSizeIterator<Item: Borrow<T::Src>>,
428) -> WriteResult<usize>
429where
430    C: ConfigCore,
431    Len: SeqLen<C>,
432    T: SchemaWrite<C>,
433{
434    if let TypeMeta::Static { size, .. } = T::TYPE_META {
435        return Ok(Len::write_bytes_needed(value.len())? + size * value.len());
436    }
437    // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
438    Ok(Len::write_bytes_needed(value.len())?
439        + (value
440            .map(|x| T::size_of(x.borrow()))
441            .try_fold(0usize, |acc, x| x.map(|x| acc + x))?))
442}
443
444#[inline(always)]
445#[allow(clippy::arithmetic_side_effects)]
446/// Variant of [`size_of_elem_iter`] specialized for slices.
447fn size_of_elem_slice<T, Len, C>(value: &[T::Src]) -> WriteResult<usize>
448where
449    C: ConfigCore,
450    Len: SeqLen<C>,
451    T: SchemaWrite<C>,
452    T::Src: Sized,
453{
454    size_of_elem_iter::<T, Len, C>(value.iter())
455}
456
457#[inline(always)]
458fn write_elem_iter<T, Len, C>(
459    mut writer: impl Writer,
460    mut src: impl ExactSizeIterator<Item: Borrow<T::Src>>,
461) -> WriteResult<()>
462where
463    C: ConfigCore,
464    Len: SeqLen<C>,
465    T: SchemaWrite<C>,
466{
467    #[cold]
468    fn short_iter() -> crate::WriteError {
469        crate::WriteError::Custom(
470            "ExactSizeIterator yielded fewer elements than its reported len()",
471        )
472    }
473
474    // Drive everything from the reported length rather than trusting the iterator to
475    // stop on its own: `0..len` caps writes at `len` (no over-run of the trusted
476    // window), and `short_iter` errors on early exhaustion (no partially initialized
477    // window, no length prefix disagreeing with the payload).
478    let len = src.len();
479    macro_rules! write_elems {
480        ($w:expr) => {{
481            Len::write($w.by_ref(), len)?;
482            for _ in 0..len {
483                let item = src.next().ok_or_else(short_iter)?;
484                T::write($w.by_ref(), item.borrow())?;
485            }
486        }};
487    }
488
489    if let TypeMeta::Static { size, .. } = T::TYPE_META {
490        #[allow(clippy::arithmetic_side_effects)]
491        let needed = Len::write_bytes_needed(len)? + size * len;
492        // SAFETY: `needed` covers the encoded length plus exactly `len` items, which is
493        // what `write_elems!` writes, fully initializing the trusted window. It writes
494        // at most `len` items (never past the window) and errors before `finish` if the
495        // iterator is short, satisfying the "no error implies fully initialized" contract.
496        let mut writer = unsafe { writer.as_trusted_for(needed) }?;
497        write_elems!(writer);
498        writer.finish()?;
499        return Ok(());
500    }
501
502    write_elems!(writer);
503    Ok(())
504}
505
506#[inline(always)]
507#[cfg(feature = "alloc")]
508fn write_elem_iter_prealloc_check<T, Len, C>(
509    writer: impl Writer,
510    src: impl ExactSizeIterator<Item: Borrow<T::Src>>,
511) -> WriteResult<()>
512where
513    C: ConfigCore,
514    Len: SeqLen<C>,
515    T: SchemaWrite<C>,
516    T::Src: Sized,
517{
518    Len::prealloc_check::<T::Src>(src.len())?;
519    write_elem_iter::<T, Len, C>(writer, src)
520}
521
522#[inline(always)]
523#[allow(clippy::arithmetic_side_effects)]
524/// Variant of [`write_elem_iter`] specialized for slices, which can opt into
525/// an optimized implementation for bytes (`u8`s).
526fn write_elem_slice<T, Len, C>(mut writer: impl Writer, src: &[T::Src]) -> WriteResult<()>
527where
528    C: ConfigCore,
529    Len: SeqLen<C>,
530    T: SchemaWrite<C>,
531    T::Src: Sized,
532{
533    if let TypeMeta::Static {
534        size,
535        zero_copy: true,
536    } = T::TYPE_META
537    {
538        let needed = Len::write_bytes_needed(src.len())? + src.len() * size;
539        // SAFETY: `needed` is the size of the encoded length plus the size of the slice (bytes).
540        // `Len::write` and `writer.write(src)` will write `needed` bytes,
541        // fully initializing the trusted window.
542        let mut writer = unsafe { writer.as_trusted_for(needed) }?;
543        Len::write(writer.by_ref(), src.len())?;
544        // SAFETY: `T::Src` is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
545        unsafe { writer.write_slice_t(src)? };
546        writer.finish()?;
547        return Ok(());
548    }
549    write_elem_iter::<T, Len, C>(writer, src.iter())
550}
551
552#[inline(always)]
553#[cfg(feature = "alloc")]
554fn write_elem_slice_prealloc_check<T, Len, C>(
555    writer: impl Writer,
556    src: &[T::Src],
557) -> WriteResult<()>
558where
559    C: ConfigCore,
560    Len: SeqLen<C>,
561    T: SchemaWrite<C>,
562    T::Src: Sized,
563{
564    Len::prealloc_check::<T::Src>(src.len())?;
565    write_elem_slice::<T, Len, C>(writer, src)
566}
567
568#[cfg(all(test, feature = "std", feature = "derive"))]
569mod tests {
570    #![allow(clippy::arithmetic_side_effects)]
571
572    use {
573        crate::{
574            Deserialize, ReadError, ReadResult, SchemaRead, SchemaReadContext, SchemaWrite,
575            Serialize, TypeMeta, UninitBuilder, WriteError, WriteResult, ZeroCopy,
576            config::{self, Config, ConfigCore, Configuration, DefaultConfig},
577            containers, context, deserialize, deserialize_exact, deserialize_mut,
578            error::{self, invalid_tag_encoding},
579            io::{Reader, Writer, test_util::NoBorrowReader},
580            len::{BincodeLen, FixIntLen, UseIntLen},
581            pod_wrapper,
582            proptest_config::proptest_cfg,
583            serialize,
584        },
585        bincode::Options,
586        core::{marker::PhantomData, ptr},
587        proptest::prelude::*,
588        std::{
589            alloc::Layout,
590            borrow::Cow,
591            cell::{Cell, RefCell},
592            collections::{BinaryHeap, HashMap, HashSet, VecDeque},
593            hash::{BuildHasher, Hasher},
594            mem::MaybeUninit,
595            net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
596            num::{
597                NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize,
598                NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
599            },
600            ops::{Bound, Deref, DerefMut, Range, RangeInclusive},
601            rc::Rc,
602            result::Result,
603            sync::{Arc, Mutex, RwLock},
604            time::{Duration, SystemTime, UNIX_EPOCH},
605        },
606    };
607
608    #[cfg(target_endian = "little")]
609    #[derive(
610        serde::Serialize,
611        serde::Deserialize,
612        Debug,
613        PartialEq,
614        Eq,
615        Ord,
616        PartialOrd,
617        SchemaWrite,
618        SchemaRead,
619        proptest_derive::Arbitrary,
620        Hash,
621        Clone,
622        Copy,
623    )]
624    #[wincode(internal)]
625    #[repr(C)]
626    struct StructZeroCopy {
627        a: u128,
628        b: i128,
629        c: u64,
630        d: i64,
631        e: u32,
632        f: i32,
633        ar1: [u8; 8],
634        g: u16,
635        h: i16,
636        ar2: [u8; 12],
637        i: u8,
638        j: i8,
639        ar3: [u8; 14],
640    }
641
642    #[cfg(not(target_endian = "little"))]
643    #[derive(
644        serde::Serialize,
645        serde::Deserialize,
646        Debug,
647        PartialEq,
648        Eq,
649        Ord,
650        PartialOrd,
651        SchemaWrite,
652        SchemaRead,
653        proptest_derive::Arbitrary,
654        Hash,
655        Clone,
656        Copy,
657    )]
658    #[wincode(internal)]
659    #[repr(C)]
660    struct StructZeroCopy {
661        byte: u8,
662        ar: [u8; 32],
663    }
664
665    #[derive(
666        serde::Serialize,
667        serde::Deserialize,
668        Debug,
669        PartialEq,
670        Eq,
671        Ord,
672        PartialOrd,
673        SchemaWrite,
674        SchemaRead,
675        proptest_derive::Arbitrary,
676        Hash,
677    )]
678    #[wincode(internal)]
679    struct StructStatic {
680        a: u64,
681        b: bool,
682        e: [u8; 32],
683    }
684
685    #[derive(
686        serde::Serialize,
687        serde::Deserialize,
688        Debug,
689        PartialEq,
690        Eq,
691        Ord,
692        PartialOrd,
693        SchemaWrite,
694        SchemaRead,
695        proptest_derive::Arbitrary,
696        Hash,
697    )]
698    #[wincode(internal)]
699    struct StructNonStatic {
700        a: u64,
701        b: bool,
702        e: String,
703    }
704
705    #[test]
706    fn struct_zero_copy_derive_size() {
707        #[cfg(target_endian = "little")]
708        let size = size_of::<u128>()
709            + size_of::<i128>()
710            + size_of::<u64>()
711            + size_of::<i64>()
712            + size_of::<u32>()
713            + size_of::<i32>()
714            + size_of::<[u8; 8]>()
715            + size_of::<u16>()
716            + size_of::<i16>()
717            + size_of::<[u8; 12]>()
718            + size_of::<u8>()
719            + size_of::<i8>()
720            + size_of::<[u8; 14]>();
721        #[cfg(not(target_endian = "little"))]
722        let size = size_of::<u8>() + size_of::<[u8; 32]>();
723        let expected = TypeMeta::Static {
724            size,
725            zero_copy: true,
726        };
727        assert_eq!(
728            <StructZeroCopy as SchemaWrite<DefaultConfig>>::TYPE_META,
729            expected
730        );
731        assert_eq!(
732            <StructZeroCopy as SchemaRead<'_, DefaultConfig>>::TYPE_META,
733            expected
734        );
735    }
736
737    #[test]
738    fn struct_zero_copy_transparent_derive_size() {
739        #[derive(SchemaWrite, SchemaRead)]
740        #[wincode(internal)]
741        #[repr(transparent)]
742        struct Address([u8; 32]);
743
744        let expected = TypeMeta::Static {
745            size: size_of::<[u8; 32]>(),
746            zero_copy: true,
747        };
748        assert_eq!(<Address as SchemaWrite<DefaultConfig>>::TYPE_META, expected);
749        assert_eq!(
750            <Address as SchemaRead<'_, DefaultConfig>>::TYPE_META,
751            expected
752        );
753    }
754
755    #[test]
756    fn struct_static_derive_size() {
757        let expected = TypeMeta::Static {
758            size: size_of::<u64>() + size_of::<bool>() + size_of::<[u8; 32]>(),
759            zero_copy: false,
760        };
761        assert_eq!(
762            <StructStatic as SchemaWrite<DefaultConfig>>::TYPE_META,
763            expected
764        );
765        assert_eq!(
766            <StructStatic as SchemaRead<'_, DefaultConfig>>::TYPE_META,
767            expected
768        );
769    }
770
771    #[test]
772    fn struct_non_static_derive_size() {
773        let expected = TypeMeta::Dynamic;
774        assert_eq!(
775            <StructNonStatic as SchemaWrite<DefaultConfig>>::TYPE_META,
776            expected
777        );
778        assert_eq!(
779            <StructNonStatic as SchemaRead<'_, DefaultConfig>>::TYPE_META,
780            expected
781        );
782    }
783
784    #[test]
785    fn test_cell_roundtrip() {
786        let value = Cell::new(0x0123_4567_89ab_cdef_u64);
787        let serialized = serialize(&value).unwrap();
788        let deserialized: Cell<u64> = deserialize(&serialized).unwrap();
789
790        assert_eq!(value.get(), deserialized.get());
791        assert_eq!(
792            <Cell<u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
793            TypeMeta::Static {
794                size: size_of::<u64>(),
795                zero_copy: false
796            }
797        );
798        assert_eq!(
799            <Cell<u64> as SchemaRead<'_, DefaultConfig>>::TYPE_META,
800            TypeMeta::Static {
801                size: size_of::<u64>(),
802                zero_copy: true
803            }
804        );
805    }
806
807    #[test]
808    fn test_refcell_roundtrip() {
809        let value = RefCell::new(String::from("hello from a refcell"));
810        let serialized = serialize(&value).unwrap();
811        let deserialized: RefCell<String> = deserialize(&serialized).unwrap();
812
813        assert_eq!(&*value.borrow(), &*deserialized.borrow());
814        assert_eq!(
815            <RefCell<String> as SchemaWrite<DefaultConfig>>::TYPE_META,
816            TypeMeta::Dynamic
817        );
818        assert_eq!(
819            <RefCell<String> as SchemaRead<'_, DefaultConfig>>::TYPE_META,
820            TypeMeta::Dynamic
821        );
822    }
823
824    #[test]
825    fn test_refcell_write_errors_while_mutably_borrowed() {
826        let value = RefCell::new(123_u32);
827        let _borrow = value.borrow_mut();
828
829        assert!(<RefCell<u32> as SchemaWrite<DefaultConfig>>::size_of(&value).is_err());
830
831        let mut bytes = Vec::new();
832        assert!(<RefCell<u32> as SchemaWrite<DefaultConfig>>::write(&mut bytes, &value).is_err());
833        assert!(serialize(&value).is_err());
834    }
835
836    #[test]
837    fn test_refcell_unsized_slice_write() {
838        let value = RefCell::new([1_u8, 2, 3, 4]);
839        let value: &RefCell<[u8]> = &value;
840
841        let serialized = <RefCell<[u8]> as Serialize>::serialize(value).unwrap();
842        let expected = serialize(&[1_u8, 2, 3, 4][..]).unwrap();
843
844        assert_eq!(serialized, expected);
845    }
846
847    thread_local! {
848        /// TL counter for tracking drops (or lack thereof -- a leak).
849        static TL_DROP_COUNT: Cell<isize> = const { Cell::new(0) };
850    }
851
852    fn get_tl_drop_count() -> isize {
853        TL_DROP_COUNT.with(|cell| cell.get())
854    }
855
856    fn tl_drop_count_inc() {
857        TL_DROP_COUNT.with(|cell| cell.set(cell.get() + 1));
858    }
859
860    fn tl_drop_count_dec() {
861        TL_DROP_COUNT.with(|cell| cell.set(cell.get() - 1));
862    }
863
864    fn tl_drop_count_reset() {
865        TL_DROP_COUNT.with(|cell| cell.set(0));
866    }
867
868    #[must_use]
869    #[derive(Debug)]
870    /// Guard for test set up that will ensure that the TL counter is 0 at the start and end of the test.
871    struct TLDropGuard;
872
873    impl TLDropGuard {
874        fn new() -> Self {
875            assert_eq!(
876                get_tl_drop_count(),
877                0,
878                "TL counter drifted from zero -- another test may have leaked"
879            );
880            Self
881        }
882    }
883
884    impl Drop for TLDropGuard {
885        #[track_caller]
886        fn drop(&mut self) {
887            let v = get_tl_drop_count();
888            if !std::thread::panicking() {
889                assert_eq!(
890                    v, 0,
891                    "TL counter drifted from zero -- this test might have leaked"
892                );
893            }
894            tl_drop_count_reset();
895        }
896    }
897
898    #[derive(Debug, PartialEq, Eq)]
899    /// A `SchemaWrite` and `SchemaRead` that will increment the TL counter when constructed.
900    struct DropCounted;
901
902    impl Arbitrary for DropCounted {
903        type Parameters = ();
904        type Strategy = Just<Self>;
905        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
906            Just(Self::new())
907        }
908    }
909
910    impl DropCounted {
911        const TAG_BYTE: u8 = 0;
912
913        fn new() -> Self {
914            tl_drop_count_inc();
915            Self
916        }
917    }
918
919    impl Clone for DropCounted {
920        fn clone(&self) -> Self {
921            tl_drop_count_inc();
922            Self
923        }
924    }
925
926    impl Drop for DropCounted {
927        fn drop(&mut self) {
928            tl_drop_count_dec();
929        }
930    }
931
932    unsafe impl<C: Config> SchemaWrite<C> for DropCounted {
933        type Src = Self;
934
935        const TYPE_META: TypeMeta = TypeMeta::Static {
936            size: 1,
937            zero_copy: false,
938        };
939
940        fn size_of(_src: &Self::Src) -> WriteResult<usize> {
941            Ok(1)
942        }
943        fn write(writer: impl Writer, _src: &Self::Src) -> WriteResult<()> {
944            <u8 as SchemaWrite<C>>::write(writer, &Self::TAG_BYTE)?;
945            Ok(())
946        }
947    }
948
949    unsafe impl<'de, C: Config> SchemaRead<'de, C> for DropCounted {
950        type Dst = Self;
951
952        const TYPE_META: TypeMeta = TypeMeta::Static {
953            size: 1,
954            zero_copy: false,
955        };
956
957        fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
958            reader.take_byte()?;
959            // This will increment the counter.
960            dst.write(DropCounted::new());
961            Ok(())
962        }
963    }
964
965    /// A `SchemaRead` that will always error on read.
966    #[derive(Debug, Clone, Copy, PartialEq, Eq, proptest_derive::Arbitrary)]
967    struct ErrorsOnRead;
968
969    impl ErrorsOnRead {
970        const TAG_BYTE: u8 = 1;
971    }
972
973    unsafe impl<C: Config> SchemaWrite<C> for ErrorsOnRead {
974        type Src = Self;
975
976        const TYPE_META: TypeMeta = TypeMeta::Static {
977            size: 1,
978            zero_copy: false,
979        };
980
981        fn size_of(_src: &Self::Src) -> WriteResult<usize> {
982            Ok(1)
983        }
984
985        fn write(writer: impl Writer, _src: &Self::Src) -> WriteResult<()> {
986            <u8 as SchemaWrite<C>>::write(writer, &Self::TAG_BYTE)
987        }
988    }
989
990    unsafe impl<'de, C: Config> SchemaRead<'de, C> for ErrorsOnRead {
991        type Dst = Self;
992
993        const TYPE_META: TypeMeta = TypeMeta::Static {
994            size: 1,
995            zero_copy: false,
996        };
997
998        fn read(mut reader: impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
999            reader.take_byte()?;
1000            Err(error::ReadError::PointerSizedReadError)
1001        }
1002    }
1003
1004    #[derive(Debug, Clone, PartialEq, Eq, proptest_derive::Arbitrary)]
1005    enum DropCountedMaybeError {
1006        DropCounted(DropCounted),
1007        ErrorsOnRead(ErrorsOnRead),
1008    }
1009
1010    unsafe impl<C: Config> SchemaWrite<C> for DropCountedMaybeError {
1011        type Src = Self;
1012
1013        const TYPE_META: TypeMeta = TypeMeta::Static {
1014            size: 1,
1015            zero_copy: false,
1016        };
1017
1018        fn size_of(src: &Self::Src) -> WriteResult<usize> {
1019            match src {
1020                DropCountedMaybeError::DropCounted(v) => {
1021                    <DropCounted as SchemaWrite<C>>::size_of(v)
1022                }
1023                DropCountedMaybeError::ErrorsOnRead(v) => {
1024                    <ErrorsOnRead as SchemaWrite<C>>::size_of(v)
1025                }
1026            }
1027        }
1028
1029        fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1030            match src {
1031                DropCountedMaybeError::DropCounted(v) => {
1032                    <DropCounted as SchemaWrite<C>>::write(writer, v)
1033                }
1034                DropCountedMaybeError::ErrorsOnRead(v) => {
1035                    <ErrorsOnRead as SchemaWrite<C>>::write(writer, v)
1036                }
1037            }
1038        }
1039    }
1040
1041    unsafe impl<'de, C: Config> SchemaRead<'de, C> for DropCountedMaybeError {
1042        type Dst = Self;
1043
1044        const TYPE_META: TypeMeta = TypeMeta::Static {
1045            size: 1,
1046            zero_copy: false,
1047        };
1048
1049        fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1050            let byte = <u8 as SchemaRead<'de, C>>::get(reader)?;
1051            match byte {
1052                DropCounted::TAG_BYTE => {
1053                    dst.write(DropCountedMaybeError::DropCounted(DropCounted::new()));
1054                    Ok(())
1055                }
1056                ErrorsOnRead::TAG_BYTE => Err(error::ReadError::PointerSizedReadError),
1057                _ => Err(invalid_tag_encoding(byte as usize)),
1058            }
1059        }
1060    }
1061
1062    #[test]
1063    fn drop_count_sanity() {
1064        let _guard = TLDropGuard::new();
1065        // Ensure our incrementing counter works
1066        let serialized = { serialize(&[DropCounted::new(), DropCounted::new()]).unwrap() };
1067        let _deserialized: [DropCounted; 2] = deserialize(&serialized).unwrap();
1068        assert_eq!(get_tl_drop_count(), 2);
1069    }
1070
1071    #[test]
1072    fn drop_count_maybe_error_sanity() {
1073        let _guard = TLDropGuard::new();
1074        let serialized =
1075            { serialize(&[DropCountedMaybeError::DropCounted(DropCounted::new())]).unwrap() };
1076        let _deserialized: [DropCountedMaybeError; 1] = deserialize(&serialized).unwrap();
1077        assert_eq!(get_tl_drop_count(), 1);
1078
1079        let serialized = {
1080            serialize(&[
1081                DropCountedMaybeError::DropCounted(DropCounted::new()),
1082                DropCountedMaybeError::ErrorsOnRead(ErrorsOnRead),
1083            ])
1084            .unwrap()
1085        };
1086        let _deserialized: ReadResult<[DropCountedMaybeError; 2]> = deserialize(&serialized);
1087    }
1088
1089    /// Test that the derive macro handles drops of initialized fields on partially initialized structs.
1090    #[test]
1091    fn test_struct_derive_handles_partial_drop() {
1092        /// Represents a struct that would leak if the derive macro didn't handle drops of initialized fields
1093        /// on error.
1094        #[derive(SchemaWrite, SchemaRead, proptest_derive::Arbitrary, Debug, PartialEq, Eq)]
1095        #[wincode(internal)]
1096        struct CouldLeak {
1097            data: DropCountedMaybeError,
1098            data2: DropCountedMaybeError,
1099            data3: DropCountedMaybeError,
1100        }
1101
1102        let _guard = TLDropGuard::new();
1103        proptest!(proptest_cfg(), |(could_leak: CouldLeak)| {
1104            let serialized = serialize(&could_leak).unwrap();
1105            let deserialized = CouldLeak::deserialize(&serialized);
1106            if let Ok(deserialized) = deserialized {
1107                prop_assert_eq!(could_leak, deserialized);
1108            }
1109        });
1110    }
1111
1112    // Odd use case, but it's technically valid so we test it.
1113    #[test]
1114    fn test_vec_of_references_borrows_from_input() {
1115        #[derive(
1116            SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy,
1117        )]
1118        #[wincode(internal)]
1119        #[repr(transparent)]
1120        struct BigBytes([u8; 512]);
1121        proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<BigBytes>(), 0..=8))| {
1122            // Serialize as owned bytes.
1123            let bytes = serialize(&vec).unwrap();
1124            let borrowed: Vec<&BigBytes> = deserialize(&bytes).unwrap();
1125
1126            prop_assert_eq!(borrowed.len(), vec.len());
1127            let start = bytes.as_ptr().addr();
1128            let end = start + bytes.len();
1129            for (i, r) in borrowed.iter().enumerate() {
1130                // Values match
1131                prop_assert_eq!(**r, vec[i]);
1132                // References point into the input buffer
1133                let p = ptr::from_ref(*r).addr();
1134                prop_assert!(p >= start && p < end);
1135            }
1136        });
1137    }
1138
1139    // Odd use case, but it's technically valid so we test it.
1140    #[test]
1141    fn test_boxed_slice_of_references_borrows_from_input() {
1142        #[derive(
1143            SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy,
1144        )]
1145        #[wincode(internal)]
1146        #[repr(transparent)]
1147        struct BigBytes([u8; 512]);
1148        proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<BigBytes>(), 0..=8))| {
1149            let boxed: Box<[BigBytes]> = vec.into_boxed_slice();
1150            let bytes = serialize(&boxed).unwrap();
1151            let borrowed: Box<[&BigBytes]> = deserialize(&bytes).unwrap();
1152
1153            prop_assert_eq!(borrowed.len(), boxed.len());
1154            let start = bytes.as_ptr().addr();
1155            let end = start + bytes.len();
1156            for (i, &r) in borrowed.iter().enumerate() {
1157                prop_assert_eq!(*r, boxed[i]);
1158                let p = ptr::from_ref(r).addr();
1159                prop_assert!(p >= start && p < end);
1160            }
1161        });
1162    }
1163
1164    /// Test that the derive macro handles drops of initialized fields on partially initialized enums.
1165    #[test]
1166    fn test_enum_derive_handles_partial_drop() {
1167        /// Represents an enum that would leak if the derive macro didn't handle drops of initialized fields
1168        /// on error.
1169        #[derive(SchemaWrite, SchemaRead, proptest_derive::Arbitrary, Debug, PartialEq, Eq)]
1170        #[wincode(internal)]
1171        enum CouldLeak {
1172            A {
1173                a: DropCountedMaybeError,
1174                b: DropCountedMaybeError,
1175            },
1176            B(
1177                DropCountedMaybeError,
1178                DropCountedMaybeError,
1179                DropCountedMaybeError,
1180            ),
1181            C(DropCountedMaybeError),
1182            D,
1183        }
1184
1185        let _guard = TLDropGuard::new();
1186        proptest!(proptest_cfg(), |(could_leak: CouldLeak)| {
1187            let serialized = serialize(&could_leak).unwrap();
1188            let deserialized = CouldLeak::deserialize(&serialized);
1189            if let Ok(deserialized) = deserialized {
1190                prop_assert_eq!(could_leak, deserialized);
1191            }
1192        });
1193    }
1194
1195    #[test]
1196    fn test_tuple_handles_partial_drop() {
1197        let _guard = TLDropGuard::new();
1198        let serialized =
1199            { serialize(&(DropCounted::new(), DropCounted::new(), ErrorsOnRead)).unwrap() };
1200        let deserialized: ReadResult<(DropCounted, DropCounted, ErrorsOnRead)> =
1201            deserialize(&serialized);
1202        assert!(deserialized.is_err());
1203    }
1204
1205    #[test]
1206    fn test_vec_handles_partial_drop() {
1207        let _guard = TLDropGuard::new();
1208        proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100))| {
1209            let serialized = serialize(&vec).unwrap();
1210            let deserialized = <Vec<DropCountedMaybeError>>::deserialize(&serialized);
1211            if let Ok(deserialized) = deserialized {
1212                prop_assert_eq!(vec, deserialized);
1213            }
1214        });
1215    }
1216
1217    /// Test that reading a `SmallVec` drops the elements it initialized before an
1218    /// error (via `SliceDropGuard`) and frees the reserved backing allocation
1219    /// (via the in-place guard in the `SchemaRead` impl). The element leak is
1220    /// caught by `TLDropGuard`; the allocation leak is only caught under Miri.
1221    #[cfg(feature = "smallvec")]
1222    #[test]
1223    fn test_smallvec_handles_partial_drop() {
1224        use smallvec::SmallVec;
1225        // Inline capacity spans both the inline (`len <= 4`) and spilled cases.
1226        type SmallVec4<T> = SmallVec<[T; 4]>;
1227
1228        let _guard = TLDropGuard::new();
1229        proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..16).prop_map(SmallVec4::from_vec))| {
1230            let serialized = serialize(&vec).unwrap();
1231            let deserialized = <SmallVec4<DropCountedMaybeError>>::deserialize(&serialized);
1232            if let Ok(deserialized) = deserialized {
1233                prop_assert_eq!(vec, deserialized);
1234            }
1235        });
1236    }
1237
1238    #[test]
1239    fn test_vec_deque_handles_partial_drop() {
1240        let _guard = TLDropGuard::new();
1241        proptest!(proptest_cfg(), |(vec in proptest::collection::vec_deque(any::<DropCountedMaybeError>(), 0..100))| {
1242            let serialized = serialize(&vec).unwrap();
1243            let deserialized = <VecDeque<DropCountedMaybeError>>::deserialize(&serialized);
1244            if let Ok(deserialized) = deserialized {
1245                prop_assert_eq!(vec, deserialized);
1246            }
1247        });
1248    }
1249
1250    #[test]
1251    fn test_boxed_slice_handles_partial_drop() {
1252        let _guard = TLDropGuard::new();
1253        proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100).prop_map(|vec| vec.into_boxed_slice()))| {
1254            let serialized = serialize(&slice).unwrap();
1255            let deserialized = <Box<[DropCountedMaybeError]>>::deserialize(&serialized);
1256            if let Ok(deserialized) = deserialized {
1257                prop_assert_eq!(slice, deserialized);
1258            }
1259        });
1260    }
1261
1262    #[test]
1263    fn test_rc_slice_handles_partial_drop() {
1264        let _guard = TLDropGuard::new();
1265        proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100).prop_map(Rc::from))| {
1266            let serialized = serialize(&slice).unwrap();
1267            let deserialized = <Rc<[DropCountedMaybeError]>>::deserialize(&serialized);
1268            if let Ok(deserialized) = deserialized {
1269                prop_assert_eq!(slice, deserialized);
1270            }
1271        });
1272    }
1273
1274    #[test]
1275    fn test_arc_slice_handles_partial_drop() {
1276        let _guard = TLDropGuard::new();
1277        proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100).prop_map(Arc::from))| {
1278            let serialized = serialize(&slice).unwrap();
1279            let deserialized = <Arc<[DropCountedMaybeError]>>::deserialize(&serialized);
1280            if let Ok(deserialized) = deserialized {
1281                prop_assert_eq!(slice, deserialized);
1282            }
1283        });
1284    }
1285
1286    #[test]
1287    fn test_arc_handles_drop() {
1288        let _guard = TLDropGuard::new();
1289        proptest!(proptest_cfg(), |(data in any::<DropCountedMaybeError>().prop_map(Rc::from))| {
1290            let serialized = serialize(&data).unwrap();
1291            let deserialized = deserialize(&serialized);
1292            if let Ok(deserialized) = deserialized {
1293                prop_assert_eq!(data, deserialized);
1294            }
1295        });
1296    }
1297
1298    #[test]
1299    fn test_rc_handles_drop() {
1300        let _guard = TLDropGuard::new();
1301        proptest!(proptest_cfg(), |(data in any::<DropCountedMaybeError>().prop_map(Rc::from))| {
1302            let serialized = serialize(&data).unwrap();
1303            let deserialized = deserialize(&serialized);
1304            if let Ok(deserialized) = deserialized {
1305                prop_assert_eq!(data, deserialized);
1306            }
1307        });
1308    }
1309
1310    #[test]
1311    fn test_box_handles_drop() {
1312        let _guard = TLDropGuard::new();
1313        proptest!(proptest_cfg(), |(data in any::<DropCountedMaybeError>().prop_map(Box::new))| {
1314            let serialized = serialize(&data).unwrap();
1315            let deserialized = deserialize(&serialized);
1316            if let Ok(deserialized) = deserialized {
1317                prop_assert_eq!(data, deserialized);
1318            }
1319        });
1320    }
1321
1322    #[test]
1323    fn test_array_handles_partial_drop() {
1324        let _guard = TLDropGuard::new();
1325
1326        proptest!(proptest_cfg(), |(array in proptest::array::uniform32(any::<DropCountedMaybeError>()))| {
1327            let serialized = serialize(&array).unwrap();
1328            let deserialized = <[DropCountedMaybeError; 32]>::deserialize(&serialized);
1329            if let Ok(deserialized) = deserialized {
1330                prop_assert_eq!(array, deserialized);
1331            }
1332        });
1333    }
1334
1335    #[test]
1336    fn test_uninit_builder_handles_partial_drop() {
1337        #[derive(SchemaWrite, UninitBuilder, Debug, proptest_derive::Arbitrary)]
1338        #[wincode(internal)]
1339        struct Test {
1340            a: DropCounted,
1341            b: DropCounted,
1342            c: DropCounted,
1343        }
1344
1345        {
1346            let _guard = TLDropGuard::new();
1347            proptest!(proptest_cfg(), |(test: Test)| {
1348                let serialized = serialize(&test).unwrap();
1349                let mut test = MaybeUninit::<Test>::uninit();
1350                let mut reader = serialized.as_slice();
1351                let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut test);
1352                builder.read_a(reader.by_ref())?.read_b(reader.by_ref())?;
1353                prop_assert!(!builder.is_init());
1354                // Struct is not fully initialized, so the two initialized fields should be dropped.
1355            });
1356        }
1357
1358        #[derive(SchemaWrite, UninitBuilder, Debug, proptest_derive::Arbitrary)]
1359        #[wincode(internal)]
1360        // Same test, but with a tuple struct.
1361        struct TestTuple(DropCounted, DropCounted);
1362
1363        {
1364            let _guard = TLDropGuard::new();
1365            proptest!(proptest_cfg(), |(test: TestTuple)| {
1366                let serialized = serialize(&test).unwrap();
1367                let mut test = MaybeUninit::<TestTuple>::uninit();
1368                let reader = &mut serialized.as_slice();
1369                let mut builder = TestTupleUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut test);
1370                builder.read_0(reader)?;
1371                prop_assert!(!builder.is_init());
1372                // Struct is not fully initialized, so the first initialized field should be dropped.
1373            });
1374        }
1375    }
1376
1377    #[test]
1378    fn test_uninit_builder_nested_builder_handles_partial_drop() {
1379        #[derive(SchemaWrite, SchemaRead, UninitBuilder, Debug, proptest_derive::Arbitrary)]
1380        #[wincode(internal)]
1381        struct Inner {
1382            a: DropCounted,
1383            b: DropCounted,
1384            c: DropCounted,
1385        }
1386
1387        #[derive(SchemaWrite, UninitBuilder, Debug, proptest_derive::Arbitrary)]
1388        #[wincode(internal)]
1389        struct Test {
1390            inner: Inner,
1391            b: DropCounted,
1392        }
1393
1394        {
1395            let _guard = TLDropGuard::new();
1396            proptest!(proptest_cfg(), |(test: Test)| {
1397                let serialized = serialize(&test).unwrap();
1398                let mut test = MaybeUninit::<Test>::uninit();
1399                let mut reader = serialized.as_slice();
1400                let mut outer_builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut test);
1401                unsafe {
1402                    outer_builder.init_inner_with(|inner| {
1403                        let mut inner_builder = InnerUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(inner);
1404                        inner_builder.read_a(reader.by_ref())?;
1405                        inner_builder.read_b(reader.by_ref())?;
1406                        inner_builder.read_c(reader.by_ref())?;
1407                        assert!(inner_builder.is_init());
1408                        inner_builder.finish();
1409                        Ok(())
1410                    })?;
1411                }
1412                // Outer struct is not fully initialized, so the inner struct should be dropped.
1413            });
1414        }
1415    }
1416
1417    #[test]
1418    fn test_uninit_builder_nested_fully_initialized() {
1419        #[derive(
1420            SchemaWrite, SchemaRead, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary,
1421        )]
1422        #[wincode(internal)]
1423        struct Inner {
1424            a: DropCounted,
1425            b: DropCounted,
1426            c: DropCounted,
1427        }
1428
1429        #[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1430        #[wincode(internal)]
1431        struct Test {
1432            inner: Inner,
1433            b: DropCounted,
1434        }
1435
1436        {
1437            let _guard = TLDropGuard::new();
1438            proptest!(proptest_cfg(), |(test: Test)| {
1439                let serialized = serialize(&test).unwrap();
1440                let mut uninit = MaybeUninit::<Test>::uninit();
1441                let mut reader = serialized.as_slice();
1442                let mut outer_builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1443                unsafe {
1444                    outer_builder.init_inner_with(|inner| {
1445                        let mut inner_builder = InnerUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(inner);
1446                        inner_builder.read_a(reader.by_ref())?;
1447                        inner_builder.read_b(reader.by_ref())?;
1448                        inner_builder.read_c(reader.by_ref())?;
1449                        assert!(inner_builder.is_init());
1450                        inner_builder.finish();
1451                        Ok(())
1452                    })?;
1453                }
1454                outer_builder.read_b(reader.by_ref())?;
1455                prop_assert!(outer_builder.is_init());
1456                outer_builder.finish();
1457                let init = unsafe { uninit.assume_init() };
1458                prop_assert_eq!(test, init);
1459            });
1460        }
1461    }
1462
1463    #[test]
1464    fn test_uninit_builder() {
1465        #[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1466        #[wincode(internal)]
1467        struct Test {
1468            a: Vec<u8>,
1469            b: [u8; 32],
1470            c: u64,
1471        }
1472
1473        proptest!(proptest_cfg(), |(test: Test)| {
1474            let serialized = serialize(&test).unwrap();
1475            let mut uninit = MaybeUninit::<Test>::uninit();
1476            let mut reader = serialized.as_slice();
1477            let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1478            builder
1479                .read_a(reader.by_ref())?
1480                .read_b(reader.by_ref())?
1481                .write_c(test.c);
1482            prop_assert!(builder.is_init());
1483            builder.finish();
1484            let init = unsafe { uninit.assume_init() };
1485            prop_assert_eq!(test, init);
1486        });
1487    }
1488
1489    #[test]
1490    fn test_uninit_builder_with_type_then_const_default_generics() {
1491        #[derive(UninitBuilder)]
1492        #[wincode(internal)]
1493        #[repr(C)]
1494        struct Foo<T = u16, const N: usize = 4>
1495        where
1496            T: Copy,
1497        {
1498            marker: PhantomData<T>,
1499            bytes: [u8; N],
1500        }
1501
1502        let mut uninit = MaybeUninit::<Foo<u16, 4>>::uninit();
1503        let mut builder =
1504            FooUninitBuilder::<u16, 4, DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1505        builder.write_marker(PhantomData).write_bytes([1, 2, 3, 4]);
1506        assert!(builder.is_init());
1507        builder.finish();
1508
1509        // SAFETY: Both fields were initialized by the builder before it was finished.
1510        let initialized = unsafe { uninit.assume_init() };
1511        assert_eq!(initialized.bytes, [1, 2, 3, 4]);
1512    }
1513
1514    #[test]
1515    fn test_uninit_builder_uninit_ref() {
1516        #[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1517        #[wincode(internal)]
1518        struct Test {
1519            a: Vec<u8>,
1520            b: [u8; 32],
1521            c: u64,
1522        }
1523
1524        proptest!(proptest_cfg(), |(test: Test)| {
1525            let serialized = serialize(&test).unwrap();
1526            let mut uninit = MaybeUninit::<Test>::uninit();
1527            let mut reader = serialized.as_slice();
1528            let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1529            builder
1530                .read_a(reader.by_ref())?
1531                .read_b(reader.by_ref())?
1532                .write_c(test.c);
1533            prop_assert!(builder.is_init());
1534
1535            unsafe {
1536                prop_assert_eq!(builder.uninit_a_ref().assume_init_ref(), &test.a);
1537                prop_assert_eq!(builder.uninit_b_ref().assume_init_ref(), &test.b);
1538                prop_assert_eq!(builder.uninit_c_ref().assume_init_ref(), &test.c);
1539            }
1540
1541            builder.finish();
1542            let init = unsafe { uninit.assume_init() };
1543            prop_assert_eq!(test, init);
1544        });
1545    }
1546
1547    #[test]
1548    fn test_uninit_builder_sanity() {
1549        #[derive(
1550            SchemaWrite, SchemaRead, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary,
1551        )]
1552        #[wincode(internal)]
1553        struct Test {
1554            a: Vec<u8>,
1555            b: [u8; 32],
1556            c: u64,
1557        }
1558
1559        proptest!(proptest_cfg(), |(test: Test)| {
1560            let serialized = serialize(&test).unwrap();
1561            let mut uninit = MaybeUninit::<Test>::uninit();
1562            let mut reader = serialized.as_slice();
1563            let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1564            builder
1565                .read_a(reader.by_ref())?
1566                .read_b(reader.by_ref())?
1567                .write_c(test.c);
1568            prop_assert!(builder.is_init());
1569            builder.finish();
1570            let init = unsafe { uninit.assume_init() };
1571            prop_assert_eq!(test, init);
1572        });
1573    }
1574
1575    #[test]
1576    fn test_uninit_builder_with_container() {
1577        #[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1578        #[wincode(internal)]
1579        struct Test {
1580            #[wincode(with = "containers::Vec<_, UseIntLen<u16>>")]
1581            a: Vec<u8>,
1582            b: [u8; 32],
1583            c: u64,
1584        }
1585
1586        proptest!(proptest_cfg(), |(test: Test)| {
1587            let serialized = serialize(&test).unwrap();
1588            let encoded_len = u16::try_from(test.a.len()).unwrap().to_le_bytes();
1589            prop_assert_eq!(&serialized[..encoded_len.len()], &encoded_len);
1590            let mut reader = serialized.as_slice();
1591            let mut uninit = MaybeUninit::<Test>::uninit();
1592            let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1593            builder
1594                .read_a(reader.by_ref())?
1595                .read_b(reader.by_ref())?
1596                .read_c(reader)?;
1597            prop_assert!(builder.is_init());
1598            let init_mut = unsafe { builder.into_assume_init_mut() };
1599            prop_assert_eq!(&test, init_mut);
1600            // Ensure `uninit` is marked initialized so fields are dropped.
1601            let init = unsafe { uninit.assume_init() };
1602            prop_assert_eq!(test, init);
1603        });
1604    }
1605
1606    #[test]
1607    fn test_uninit_builder_extensions_with_reference() {
1608        #[derive(Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1609        struct Test {
1610            a: Vec<u8>,
1611            b: Option<String>,
1612        }
1613
1614        #[derive(UninitBuilder, Debug, PartialEq, Eq)]
1615        #[wincode(internal)]
1616        struct TestRef<'a> {
1617            a: &'a [u8],
1618            b: Option<&'a str>,
1619        }
1620
1621        proptest!(proptest_cfg(), |(test: Test)| {
1622            let mut uninit = MaybeUninit::<TestRef>::uninit();
1623            let mut builder = TestRefUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1624            builder
1625                .write_a(test.a.as_slice())
1626                .write_b(test.b.as_deref());
1627            prop_assert!(builder.is_init());
1628            builder.finish();
1629            let init = unsafe { uninit.assume_init() };
1630            prop_assert_eq!(test.a.as_slice(), init.a);
1631            prop_assert_eq!(test.b.as_deref(), init.b);
1632        });
1633    }
1634
1635    #[test]
1636    fn test_uninit_builder_read_borrowed() {
1637        #[derive(SchemaWrite, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1638        #[wincode(internal)]
1639        struct Test {
1640            a: Vec<u8>,
1641            b: Option<String>,
1642        }
1643
1644        #[derive(UninitBuilder, Debug, PartialEq, Eq)]
1645        #[wincode(internal)]
1646        struct TestRef<'a> {
1647            a: &'a [u8],
1648            b: Option<&'a str>,
1649        }
1650
1651        proptest!(proptest_cfg(), |(test: Test)| {
1652            let serialized = serialize(&test).unwrap();
1653            let mut uninit = MaybeUninit::<TestRef>::uninit();
1654            let mut reader = serialized.as_slice();
1655            let mut builder = TestRefUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1656            builder
1657                .read_a(reader.by_ref())?
1658                .read_b(reader.by_ref())?;
1659            prop_assert!(builder.is_init());
1660            let init = unsafe { builder.into_assume_init_mut() };
1661            prop_assert_eq!(test.a.as_slice(), init.a);
1662            prop_assert_eq!(test.b.as_deref(), init.b);
1663        });
1664    }
1665
1666    #[test]
1667    fn test_uninit_builder_read_owned_with_unrelated_lifetime() {
1668        #[derive(UninitBuilder, Debug, PartialEq, Eq)]
1669        #[wincode(internal)]
1670        struct Test<'a> {
1671            marker: PhantomData<&'a ()>,
1672            value: u8,
1673        }
1674
1675        fn read_short_lived(reader: &[u8]) -> Test<'static> {
1676            let mut uninit = MaybeUninit::<Test<'static>>::uninit();
1677            let mut builder =
1678                TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1679            builder
1680                .write_marker(PhantomData)
1681                .read_value(reader)
1682                .unwrap();
1683            builder.finish();
1684            // SAFETY: Both fields were initialized by the builder.
1685            unsafe { uninit.assume_init() }
1686        }
1687
1688        let short_lived = vec![42];
1689        let test = read_short_lived(&short_lived);
1690        drop(short_lived);
1691
1692        assert_eq!(
1693            test,
1694            Test {
1695                marker: PhantomData,
1696                value: 42,
1697            }
1698        );
1699    }
1700
1701    #[test]
1702    fn test_uninit_builder_builder_fully_initialized() {
1703        #[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1704        #[wincode(internal)]
1705        struct Test {
1706            a: DropCounted,
1707            b: DropCounted,
1708            c: DropCounted,
1709        }
1710
1711        {
1712            let _guard = TLDropGuard::new();
1713            proptest!(proptest_cfg(), |(test: Test)| {
1714                let serialized = serialize(&test).unwrap();
1715                let mut uninit = MaybeUninit::<Test>::uninit();
1716                let mut reader = serialized.as_slice();
1717                let mut builder = TestUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1718                builder
1719                    .read_a(reader.by_ref())?
1720                    .read_b(reader.by_ref())?
1721                    .read_c(reader.by_ref())?;
1722                prop_assert!(builder.is_init());
1723                let init = unsafe { builder.into_assume_init_mut() };
1724                prop_assert_eq!(&test, init);
1725
1726                let init = unsafe { uninit.assume_init() };
1727                prop_assert_eq!(test, init);
1728            });
1729        }
1730
1731        #[derive(SchemaWrite, UninitBuilder, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1732        #[wincode(internal)]
1733        // Same test, but with a tuple struct.
1734        struct TestTuple(DropCounted, DropCounted);
1735
1736        {
1737            let _guard = TLDropGuard::new();
1738            proptest!(proptest_cfg(), |(test: TestTuple)| {
1739                let serialized = serialize(&test).unwrap();
1740                let mut uninit = MaybeUninit::<TestTuple>::uninit();
1741                let mut reader = serialized.as_slice();
1742                let mut builder = TestTupleUninitBuilder::<DefaultConfig>::from_maybe_uninit_mut(&mut uninit);
1743                builder
1744                    .read_0(reader.by_ref())?
1745                    .read_1(reader.by_ref())?;
1746                assert!(builder.is_init());
1747                builder.finish();
1748
1749                let init = unsafe { uninit.assume_init() };
1750                prop_assert_eq!(test, init);
1751            });
1752        }
1753    }
1754
1755    #[test]
1756    fn test_struct_with_reference_equivalence() {
1757        #[derive(
1758            SchemaWrite, SchemaRead, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize,
1759        )]
1760        #[wincode(internal)]
1761        struct WithReference<'a> {
1762            data: &'a str,
1763            id: u64,
1764        }
1765
1766        proptest!(proptest_cfg(), |(s in any::<String>(), id in any::<u64>())| {
1767            let serialized = serialize(&WithReference { data: &s, id }).unwrap();
1768            let bincode_serialized = bincode::serialize(&WithReference { data: &s, id }).unwrap();
1769            prop_assert_eq!(&serialized, &bincode_serialized);
1770            let deserialized: WithReference = deserialize(&serialized).unwrap();
1771            let bincode_deserialized: WithReference = bincode::deserialize(&bincode_serialized).unwrap();
1772            prop_assert_eq!(deserialized, bincode_deserialized);
1773        });
1774    }
1775
1776    #[test]
1777    fn test_skipped_fields() {
1778        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1779        #[wincode(internal)]
1780        struct Test {
1781            a: StructZeroCopy,
1782            #[wincode(skip)]
1783            b: [u8; 32],
1784            c: StructStatic,
1785            #[wincode(skip(default_val = 345))]
1786            d: u32,
1787        }
1788
1789        let expected = TypeMeta::Static {
1790            size: size_of::<StructZeroCopy>()
1791                + <StructStatic as SchemaWrite<DefaultConfig>>::TYPE_META.size_assert_static(),
1792            zero_copy: false,
1793        };
1794        assert_eq!(<Test as SchemaWrite<DefaultConfig>>::TYPE_META, expected);
1795
1796        proptest!(proptest_cfg(), |(test: Test)| {
1797            let mut serialized = serialize(&test).unwrap();
1798            let mut uninit_zeroed = MaybeUninit::<Test>::uninit();
1799            Test::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
1800            let deserialized = unsafe { uninit_zeroed.assume_init() };
1801            assert_eq!(deserialized.b, [0; 32]);
1802            assert_eq!(deserialized.d, 345);
1803            let reinitialized = Test {
1804                b: test.b,
1805                d: test.d,
1806                ..deserialized
1807            };
1808            prop_assert_eq!(reinitialized, test);
1809        });
1810
1811        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1812        #[wincode(internal)]
1813        struct TestTuple(StructZeroCopy, #[wincode(skip)] u64, u32);
1814
1815        let expected = TypeMeta::Static {
1816            size: size_of::<StructZeroCopy>() + size_of::<u32>(),
1817            zero_copy: false,
1818        };
1819        assert_eq!(
1820            <TestTuple as SchemaWrite<DefaultConfig>>::TYPE_META,
1821            expected
1822        );
1823
1824        proptest!(proptest_cfg(), |(test: TestTuple)| {
1825            let mut serialized = serialize(&test).unwrap();
1826            let mut uninit_zeroed = MaybeUninit::<TestTuple>::uninit();
1827            TestTuple::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
1828            let deserialized = unsafe { uninit_zeroed.assume_init() };
1829            assert_eq!(deserialized.1, 0);
1830            let reinitialized = TestTuple(deserialized.0, test.1, deserialized.2);
1831            prop_assert_eq!(reinitialized, test);
1832        });
1833
1834        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1835        #[wincode(internal)]
1836        enum TestEnum {
1837            X([u64; 17], u8),
1838            Y(Test),
1839            Z(([u64; 16], u8), #[wincode(skip(default_val = 9))] u8, u64),
1840            W {
1841                a: u8,
1842                #[wincode(skip(default_val = 123))]
1843                b: u16,
1844                c: [u64; 17],
1845            },
1846        }
1847        let expected = TypeMeta::Static {
1848            size: size_of::<u32>() // discriminant
1849                + size_of::<u64>() * 17 + size_of::<u8>(),
1850            zero_copy: false,
1851        };
1852        assert_eq!(
1853            <TestEnum as SchemaWrite<DefaultConfig>>::TYPE_META,
1854            expected
1855        );
1856
1857        proptest!(proptest_cfg(), |(test: TestEnum)| {
1858            let mut serialized = serialize(&test).unwrap();
1859            let mut uninit_zeroed = MaybeUninit::<TestEnum>::uninit();
1860            TestEnum::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
1861
1862            let deserialized = unsafe { uninit_zeroed.assume_init() };
1863            let reinitialized = match (deserialized, &test) {
1864                (TestEnum::Y(deserialized_y), TestEnum::Y(test_y)) => {
1865                    assert_eq!(deserialized_y.b, [0; 32]);
1866                    assert_eq!(deserialized_y.d, 345);
1867                    TestEnum::Y(Test {
1868                        b: test_y.b,
1869                        d: test_y.d,
1870                        ..deserialized_y
1871                    })
1872                },
1873                (TestEnum::Z(d_0, d_1, d_2), TestEnum::Z(_, t_1, _)) => {
1874                    assert_eq!(d_1, 9);
1875                    TestEnum::Z(d_0, *t_1, d_2)
1876                },
1877                (TestEnum::W { a: d_a, b: d_b, c:  d_c }, TestEnum::W { a: _, b: test_b, c: _ }) => {
1878                    assert_eq!(d_b, 123);
1879                    TestEnum::W {
1880                        a: d_a,
1881                        b: *test_b,
1882                        c: d_c,
1883                    }
1884                },
1885                (other, _) => other
1886            };
1887            prop_assert_eq!(reinitialized, test);
1888        });
1889
1890        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1891        #[wincode(internal)]
1892        #[repr(C)]
1893        struct TestZeroCopy {
1894            a: StructZeroCopy,
1895            #[wincode(skip)]
1896            b: (),
1897            c: [u8; 16],
1898        }
1899        assert_eq!(
1900            <TestZeroCopy as SchemaWrite<DefaultConfig>>::TYPE_META,
1901            TypeMeta::Static {
1902                size: size_of::<StructZeroCopy>() + 16,
1903                zero_copy: true,
1904            }
1905        );
1906
1907        proptest!(proptest_cfg(), |(test: TestZeroCopy)| {
1908            let mut serialized = serialize(&test).unwrap();
1909            let mut uninit_zeroed = MaybeUninit::<TestZeroCopy>::uninit();
1910            TestZeroCopy::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
1911            let deserialized = unsafe { uninit_zeroed.assume_init() };
1912            prop_assert_eq!(deserialized, test);
1913        });
1914
1915        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1916        #[wincode(internal)]
1917        #[repr(C)]
1918        struct TestNonZeroCopy {
1919            a: StructZeroCopy,
1920            #[wincode(skip(default_val = [1u8; 16]))]
1921            b: [u8; 16],
1922        }
1923        assert_eq!(
1924            <TestNonZeroCopy as SchemaWrite<DefaultConfig>>::TYPE_META,
1925            TypeMeta::Static {
1926                size: size_of::<StructZeroCopy>(),
1927                zero_copy: false,
1928            }
1929        );
1930
1931        proptest!(proptest_cfg(), |(test: TestNonZeroCopy)| {
1932            let mut serialized = serialize(&test).unwrap();
1933            let mut uninit_zeroed = MaybeUninit::<TestNonZeroCopy>::uninit();
1934            TestNonZeroCopy::deserialize_into(serialized.as_mut(), &mut uninit_zeroed).unwrap();
1935            let deserialized = unsafe { uninit_zeroed.assume_init() };
1936            assert_eq!(deserialized.b, [1u8; 16]);
1937            let reinitialized = TestNonZeroCopy {
1938                b: test.b,
1939                ..deserialized
1940            };
1941            prop_assert_eq!(reinitialized, test);
1942        });
1943    }
1944
1945    #[test]
1946    fn test_enum_equivalence() {
1947        #[derive(
1948            SchemaWrite,
1949            SchemaRead,
1950            Debug,
1951            PartialEq,
1952            Eq,
1953            serde::Serialize,
1954            serde::Deserialize,
1955            Clone,
1956            proptest_derive::Arbitrary,
1957        )]
1958        #[wincode(internal)]
1959        enum Enum {
1960            A { name: String, id: u64 },
1961            B(String, Vec<u8>),
1962            C,
1963        }
1964
1965        proptest!(proptest_cfg(), |(e: Enum)| {
1966            let serialized = serialize(&e).unwrap();
1967            let bincode_serialized = bincode::serialize(&e).unwrap();
1968            prop_assert_eq!(&serialized, &bincode_serialized);
1969            let deserialized: Enum = deserialize(&serialized).unwrap();
1970            let bincode_deserialized: Enum = bincode::deserialize(&bincode_serialized).unwrap();
1971            prop_assert_eq!(deserialized, bincode_deserialized);
1972        });
1973    }
1974
1975    #[test]
1976    fn enum_with_tag_encoding_roundtrip() {
1977        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1978        #[wincode(internal, tag_encoding = "u8")]
1979        enum Enum {
1980            A { name: String, id: u64 },
1981            B(String, Vec<u8>),
1982            C,
1983        }
1984
1985        proptest!(proptest_cfg(), |(e: Enum)| {
1986            let serialized = serialize(&e).unwrap();
1987            let deserialized: Enum = deserialize(&serialized).unwrap();
1988            prop_assert_eq!(deserialized, e);
1989        });
1990    }
1991
1992    #[test]
1993    fn enum_with_custom_tag_roundtrip() {
1994        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1995        #[wincode(internal)]
1996        enum Enum {
1997            #[wincode(tag = 5)]
1998            A { name: String, id: u64 },
1999            #[wincode(tag = 8)]
2000            B(String, Vec<u8>),
2001            #[wincode(tag = 13)]
2002            C,
2003        }
2004
2005        proptest!(proptest_cfg(), |(e: Enum)| {
2006            let serialized = serialize(&e).unwrap();
2007            let deserialized: Enum = deserialize(&serialized).unwrap();
2008            prop_assert_eq!(deserialized, e);
2009        });
2010
2011        proptest!(proptest_cfg(), |(e: Enum)| {
2012            let serialized = serialize(&e).unwrap();
2013            let int: u32 = match e {
2014                Enum::A { .. } => 5,
2015                Enum::B(..) => 8,
2016                Enum::C => 13,
2017            };
2018            prop_assert_eq!(&int.to_le_bytes(), &serialized[..4]);
2019        });
2020    }
2021
2022    #[test]
2023    fn unit_enum_with_tag_encoding_static_size() {
2024        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq)]
2025        #[wincode(internal, tag_encoding = "u8")]
2026        enum Enum {
2027            A,
2028            B,
2029            C,
2030        }
2031
2032        assert!(matches!(
2033            <Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
2034            TypeMeta::Static {
2035                size: 1,
2036                zero_copy: false
2037            }
2038        ));
2039
2040        assert!(matches!(
2041            <Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
2042            TypeMeta::Static {
2043                size: 1,
2044                zero_copy: false
2045            }
2046        ));
2047    }
2048
2049    #[test]
2050    fn unit_enum_with_static_size() {
2051        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq)]
2052        #[wincode(internal)]
2053        enum Enum {
2054            A,
2055            B,
2056            C,
2057        }
2058
2059        assert!(matches!(
2060            <Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
2061            TypeMeta::Static {
2062                size: 4,
2063                zero_copy: false
2064            }
2065        ));
2066
2067        assert!(matches!(
2068            <Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
2069            TypeMeta::Static {
2070                size: 4,
2071                zero_copy: false
2072            }
2073        ));
2074    }
2075
2076    #[test]
2077    fn enum_tag_encoding() {
2078        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
2079        #[wincode(internal, tag_encoding = "u8")]
2080        enum EnumU8 {
2081            A,
2082            B,
2083            C,
2084        }
2085
2086        proptest!(proptest_cfg(), |(e: EnumU8)| {
2087            let serialized = serialize(&e).unwrap();
2088            let int = e as u8;
2089            prop_assert_eq!(&int.to_le_bytes(), &serialized[..]);
2090        });
2091
2092        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
2093        #[wincode(internal, tag_encoding = "u8")]
2094        enum EnumTupleU8 {
2095            A(u64),
2096            B(StructStatic),
2097            C(StructNonStatic),
2098        }
2099
2100        proptest!(proptest_cfg(), |(e: EnumTupleU8)| {
2101            let serialized = serialize(&e).unwrap();
2102            let int: u8 = match e {
2103                EnumTupleU8::A(_) => 0,
2104                EnumTupleU8::B(_) => 1,
2105                EnumTupleU8::C(_) => 2,
2106            };
2107            prop_assert_eq!(&int.to_le_bytes(), &serialized[..1]);
2108        });
2109
2110        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
2111        #[wincode(internal, tag_encoding = "u8")]
2112        enum EnumRecordU8 {
2113            A { id: u64 },
2114            B { data: StructStatic },
2115            C { data: StructNonStatic },
2116        }
2117
2118        proptest!(proptest_cfg(), |(e: EnumRecordU8)| {
2119            let serialized = serialize(&e).unwrap();
2120            let int: u8 = match e {
2121                EnumRecordU8::A { .. } => 0,
2122                EnumRecordU8::B { .. } => 1,
2123                EnumRecordU8::C { .. } => 2,
2124            };
2125            prop_assert_eq!(&int.to_le_bytes(), &serialized[..1]);
2126        });
2127    }
2128
2129    #[test]
2130    fn enum_static_uniform_variants() {
2131        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
2132        #[wincode(internal)]
2133        enum Enum {
2134            A {
2135                a: u64,
2136            },
2137            B {
2138                x: u32,
2139                y: u32,
2140            },
2141            C {
2142                a: u8,
2143                b: u8,
2144                c: u8,
2145                d: u8,
2146                e: u8,
2147                f: u8,
2148                g: u8,
2149                h: u8,
2150            },
2151        }
2152
2153        assert_eq!(
2154            <Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
2155            TypeMeta::Static {
2156                // (account for discriminant u32)
2157                size: 8 + 4,
2158                zero_copy: false
2159            }
2160        );
2161        assert_eq!(
2162            <Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
2163            TypeMeta::Static {
2164                // (account for discriminant u32)
2165                size: 8 + 4,
2166                zero_copy: false
2167            }
2168        );
2169
2170        proptest!(proptest_cfg(), |(e: Enum)| {
2171            let serialized = serialize(&e).unwrap();
2172            let deserialized: Enum = deserialize(&serialized).unwrap();
2173            prop_assert_eq!(deserialized, e);
2174        });
2175    }
2176
2177    #[test]
2178    fn enum_dynamic_non_uniform_variants() {
2179        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
2180        #[wincode(internal)]
2181        enum Enum {
2182            A { a: u64 },
2183            B { x: u32, y: u32 },
2184            C { a: u8, b: u8 },
2185        }
2186
2187        assert_eq!(
2188            <Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
2189            TypeMeta::Dynamic
2190        );
2191        assert_eq!(
2192            <Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
2193            TypeMeta::Dynamic
2194        );
2195
2196        proptest!(proptest_cfg(), |(e: Enum)| {
2197            let serialized = serialize(&e).unwrap();
2198            let deserialized: Enum = deserialize(&serialized).unwrap();
2199            prop_assert_eq!(deserialized, e);
2200        });
2201    }
2202
2203    #[test]
2204    fn enum_single_variant_type_meta_pass_thru() {
2205        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
2206        #[wincode(internal)]
2207        enum Enum {
2208            A { a: u8, b: [u8; 32] },
2209        }
2210
2211        // Single variant enums should use the `TypeMeta` of the variant, but the zero-copy
2212        // flag should be `false`, due to the discriminant having potentially invalid bit patterns.
2213        assert_eq!(
2214            <Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
2215            TypeMeta::Static {
2216                size: 1 + 32 + 4,
2217                zero_copy: false
2218            }
2219        );
2220        assert_eq!(
2221            <Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
2222            TypeMeta::Static {
2223                size: 1 + 32 + 4,
2224                zero_copy: false
2225            }
2226        );
2227    }
2228
2229    #[test]
2230    fn enum_unit_and_non_unit_dynamic() {
2231        #[derive(
2232            SchemaWrite,
2233            SchemaRead,
2234            Debug,
2235            PartialEq,
2236            proptest_derive::Arbitrary,
2237            serde::Serialize,
2238            serde::Deserialize,
2239        )]
2240        #[wincode(internal)]
2241        enum Enum {
2242            Unit,
2243            NonUnit(u8),
2244        }
2245
2246        assert_eq!(
2247            <Enum as SchemaWrite<DefaultConfig>>::TYPE_META,
2248            TypeMeta::Dynamic
2249        );
2250        assert_eq!(
2251            <Enum as SchemaRead<'_, DefaultConfig>>::TYPE_META,
2252            TypeMeta::Dynamic
2253        );
2254
2255        proptest!(proptest_cfg(), |(e: Enum)| {
2256            let serialized = serialize(&e).unwrap();
2257            let bincode_serialized = bincode::serialize(&e).unwrap();
2258            prop_assert_eq!(&serialized, &bincode_serialized);
2259
2260            let deserialized: Enum = deserialize(&serialized).unwrap();
2261            let bincode_deserialized: Enum = bincode::deserialize(&bincode_serialized).unwrap();
2262            prop_assert_eq!(&deserialized, &bincode_deserialized);
2263            prop_assert_eq!(deserialized, e);
2264        });
2265    }
2266
2267    #[test]
2268    fn test_enum_config_discriminant_u8() {
2269        let config = Configuration::default().with_tag_encoding::<u8>();
2270
2271        #[derive(SchemaRead, SchemaWrite, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
2272        #[wincode(internal)]
2273        enum Enum {
2274            A,
2275            B,
2276        }
2277
2278        assert_eq!(
2279            <Enum as SchemaRead<'_, _>>::type_meta(config),
2280            TypeMeta::Static {
2281                size: 1,
2282                zero_copy: false
2283            }
2284        );
2285
2286        assert_eq!(
2287            <Enum as SchemaWrite<_>>::type_meta(config),
2288            TypeMeta::Static {
2289                size: 1,
2290                zero_copy: false
2291            }
2292        );
2293
2294        proptest!(proptest_cfg(), |(e: Enum)| {
2295            let serialized = config::serialize(&e, config).unwrap();
2296            prop_assert_eq!(serialized.len(), 1);
2297            match e {
2298                Enum::A => prop_assert_eq!(serialized[0], 0),
2299                Enum::B => prop_assert_eq!(serialized[0], 1),
2300            }
2301            let deserialized: Enum = config::deserialize(&serialized, config).unwrap();
2302            prop_assert_eq!(deserialized, e);
2303        });
2304    }
2305
2306    #[test]
2307    fn test_chained_config_preserves_tag_encoding() {
2308        let config = Configuration::default()
2309            .with_tag_encoding::<u8>()
2310            .with_big_endian()
2311            .with_preallocation_size_limit::<64>();
2312
2313        #[derive(SchemaRead, SchemaWrite, Debug, PartialEq, Eq)]
2314        #[wincode(internal)]
2315        enum Enum {
2316            A,
2317            B,
2318        }
2319
2320        assert_eq!(
2321            <Enum as SchemaRead<'_, _>>::type_meta(config),
2322            TypeMeta::Static {
2323                size: 1,
2324                zero_copy: false
2325            }
2326        );
2327
2328        assert_eq!(
2329            <Enum as SchemaWrite<_>>::type_meta(config),
2330            TypeMeta::Static {
2331                size: 1,
2332                zero_copy: false
2333            }
2334        );
2335
2336        let serialized = config::serialize(&Enum::B, config).unwrap();
2337        assert_eq!(serialized, [1]);
2338
2339        let deserialized: Enum = config::deserialize(&serialized, config).unwrap();
2340        assert_eq!(deserialized, Enum::B);
2341    }
2342
2343    #[test]
2344    fn test_enum_config_discriminant_override() {
2345        let config = Configuration::default().with_tag_encoding::<u8>();
2346
2347        #[derive(SchemaRead, SchemaWrite, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
2348        #[wincode(internal, tag_encoding = "u32")]
2349        enum Enum {
2350            A,
2351            B,
2352        }
2353
2354        assert_eq!(
2355            <Enum as SchemaRead<'_, _>>::type_meta(config),
2356            TypeMeta::Static {
2357                size: 4,
2358                zero_copy: false
2359            }
2360        );
2361
2362        assert_eq!(
2363            <Enum as SchemaWrite<_>>::type_meta(config),
2364            TypeMeta::Static {
2365                size: 4,
2366                zero_copy: false
2367            }
2368        );
2369
2370        proptest!(proptest_cfg(), |(e: Enum)| {
2371            let serialized = config::serialize(&e, config).unwrap();
2372            prop_assert_eq!(serialized.len(), 4);
2373            let discriminant = u32::from_le_bytes(serialized[0..4].try_into().unwrap());
2374            match e {
2375                Enum::A => prop_assert_eq!(discriminant, 0u32),
2376                Enum::B => prop_assert_eq!(discriminant, 1u32),
2377            }
2378            let deserialized: Enum = config::deserialize(&serialized, config).unwrap();
2379            prop_assert_eq!(deserialized, e);
2380        });
2381    }
2382
2383    #[test]
2384    fn test_enum_config_discriminant_u8_custom_tag() {
2385        let config = Configuration::default().with_tag_encoding::<u8>();
2386
2387        #[derive(SchemaRead, SchemaWrite, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
2388        #[wincode(internal)]
2389        enum Enum {
2390            #[wincode(tag = 2)]
2391            A,
2392            #[wincode(tag = 3)]
2393            B,
2394            #[wincode(tag = 5)]
2395            C,
2396        }
2397
2398        proptest!(proptest_cfg(), |(e: Enum)| {
2399            let serialized = config::serialize(&e, config).unwrap();
2400            prop_assert_eq!(serialized.len(), 1);
2401            match e {
2402                Enum::A => prop_assert_eq!(serialized[0], 2),
2403                Enum::B => prop_assert_eq!(serialized[0], 3),
2404                Enum::C => prop_assert_eq!(serialized[0], 5),
2405            }
2406            let deserialized: Enum = config::deserialize(&serialized, config).unwrap();
2407            prop_assert_eq!(deserialized, e);
2408        });
2409    }
2410
2411    #[test]
2412    fn test_enum_tag_overflow_size_of_matches_write() {
2413        // `size_of`/`serialized_size` must reject a discriminant that overflows the tag
2414        // encoding, just like `serialize`/`serialize_into` do.
2415        let u8_tag_cfg = Configuration::default().with_tag_encoding::<u8>();
2416
2417        #[derive(SchemaWrite)]
2418        #[wincode(internal)]
2419        enum NarrowTagEnum {
2420            #[wincode(tag = 0)]
2421            Fits(u8),
2422            #[wincode(tag = 256)]
2423            Overflows(u8),
2424        }
2425
2426        let fits = NarrowTagEnum::Fits(1);
2427        assert_eq!(config::serialized_size(&fits, u8_tag_cfg).unwrap(), 2);
2428        assert_eq!(config::serialize(&fits, u8_tag_cfg).unwrap(), [0, 1]);
2429
2430        let overflow = NarrowTagEnum::Overflows(1);
2431        assert!(matches!(
2432            config::serialize(&overflow, u8_tag_cfg),
2433            Err(WriteError::TagEncodingOverflow(_))
2434        ));
2435        assert!(matches!(
2436            config::serialize_into(&mut vec![], &overflow, u8_tag_cfg),
2437            Err(WriteError::TagEncodingOverflow(_))
2438        ));
2439        assert!(matches!(
2440            config::serialized_size(&overflow, u8_tag_cfg),
2441            Err(WriteError::TagEncodingOverflow(_))
2442        ));
2443    }
2444
2445    #[test]
2446    fn test_phantom_data() {
2447        let val = PhantomData::<StructStatic>;
2448        let serialized = serialize(&val).unwrap();
2449        let bincode_serialized = bincode::serialize(&val).unwrap();
2450        assert_eq!(&serialized, &bincode_serialized);
2451        assert_eq!(
2452            <PhantomData<StructStatic> as SchemaWrite<DefaultConfig>>::size_of(&val).unwrap(),
2453            bincode::serialized_size(&val).unwrap() as usize
2454        );
2455        let deserialized: PhantomData<StructStatic> = deserialize(&serialized).unwrap();
2456        let bincode_deserialized: PhantomData<StructStatic> =
2457            bincode::deserialize(&bincode_serialized).unwrap();
2458        assert_eq!(deserialized, bincode_deserialized);
2459    }
2460
2461    #[test]
2462    fn test_unit() {
2463        let serialized = serialize(&()).unwrap();
2464        let bincode_serialized = bincode::serialize(&()).unwrap();
2465        assert_eq!(&serialized, &bincode_serialized);
2466        assert_eq!(
2467            <() as SchemaWrite<DefaultConfig>>::size_of(&()).unwrap(),
2468            bincode::serialized_size(&()).unwrap() as usize
2469        );
2470        assert!(deserialize::<()>(&serialized).is_ok());
2471        assert!(bincode::deserialize::<()>(&bincode_serialized).is_ok());
2472    }
2473
2474    #[test]
2475    fn test_duration_varint_type_meta_dynamic() {
2476        let config = Configuration::default().with_varint_encoding();
2477
2478        assert_eq!(
2479            <Duration as SchemaWrite<_>>::type_meta(config),
2480            TypeMeta::Dynamic
2481        );
2482        assert_eq!(
2483            <Duration as SchemaRead<'_, _>>::type_meta(config),
2484            TypeMeta::Dynamic
2485        );
2486
2487        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
2488        #[wincode(internal)]
2489        struct WithDuration {
2490            a: u8,
2491            d: Duration,
2492            b: u8,
2493        }
2494
2495        assert_eq!(
2496            <WithDuration as SchemaWrite<_>>::type_meta(config),
2497            TypeMeta::Dynamic
2498        );
2499        assert_eq!(
2500            <WithDuration as SchemaRead<'_, _>>::type_meta(config),
2501            TypeMeta::Dynamic
2502        );
2503
2504        let val = WithDuration {
2505            a: 1,
2506            d: Duration::new(0, 0),
2507            b: 2,
2508        };
2509
2510        // u64(0) + u32(0) use varint -> 1 byte each.
2511        assert_eq!(config::serialized_size(&val.d, config).unwrap(), 2);
2512
2513        // Buffer is intentionally < fixed-width size (1 + 12 + 1 = 14). Old (incorrect) TYPE_META
2514        // would try to reserve 14 bytes via a trusted window and fail with WriteSizeLimit.
2515        let mut buf = [0xAAu8; 13];
2516        let written = {
2517            let buf_len = buf.len();
2518            let mut writer: &mut [u8] = &mut buf;
2519            config::serialize_into(&mut writer, &val, config).unwrap();
2520            buf_len - writer.len()
2521        };
2522        assert_eq!(written, 4);
2523        assert_eq!(&buf[..written], &[1, 0, 0, 2]);
2524        assert!(buf[written..].iter().all(|&b| b == 0xAA));
2525
2526        let roundtrip: WithDuration = config::deserialize(&buf[..written], config).unwrap();
2527        assert_eq!(roundtrip, val);
2528    }
2529
2530    #[test]
2531    fn test_system_time_varint_type_meta_dynamic() {
2532        let config = Configuration::default().with_varint_encoding();
2533
2534        assert_eq!(
2535            <SystemTime as SchemaWrite<_>>::type_meta(config),
2536            TypeMeta::Dynamic
2537        );
2538        assert_eq!(
2539            <SystemTime as SchemaRead<'_, _>>::type_meta(config),
2540            TypeMeta::Dynamic
2541        );
2542
2543        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
2544        #[wincode(internal)]
2545        struct WithSystemTime {
2546            a: u8,
2547            t: SystemTime,
2548            b: u8,
2549        }
2550
2551        assert_eq!(
2552            <WithSystemTime as SchemaWrite<_>>::type_meta(config),
2553            TypeMeta::Dynamic
2554        );
2555        assert_eq!(
2556            <WithSystemTime as SchemaRead<'_, _>>::type_meta(config),
2557            TypeMeta::Dynamic
2558        );
2559
2560        let val = WithSystemTime {
2561            a: 1,
2562            t: UNIX_EPOCH,
2563            b: 2,
2564        };
2565
2566        // SystemTime encodes as Duration since UNIX_EPOCH.
2567        assert_eq!(config::serialized_size(&val.t, config).unwrap(), 2);
2568
2569        let mut buf = [0xAAu8; 13];
2570        let written = {
2571            let buf_len = buf.len();
2572            let mut writer: &mut [u8] = &mut buf;
2573            config::serialize_into(&mut writer, &val, config).unwrap();
2574            buf_len - writer.len()
2575        };
2576        assert_eq!(written, 4);
2577        assert_eq!(&buf[..written], &[1, 0, 0, 2]);
2578        assert!(buf[written..].iter().all(|&b| b == 0xAA));
2579
2580        let roundtrip: WithSystemTime = config::deserialize(&buf[..written], config).unwrap();
2581        assert_eq!(roundtrip, val);
2582    }
2583
2584    #[test]
2585    fn test_borrowed_bytes() {
2586        #[derive(
2587            SchemaWrite, SchemaRead, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize,
2588        )]
2589        #[wincode(internal)]
2590        struct BorrowedBytes<'a> {
2591            bytes: &'a [u8],
2592        }
2593
2594        proptest!(proptest_cfg(), |(bytes in proptest::collection::vec(any::<u8>(), 0..=100))| {
2595            let val = BorrowedBytes { bytes: &bytes };
2596            let bincode_serialized = bincode::serialize(&val).unwrap();
2597            let schema_serialized = serialize(&val).unwrap();
2598            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2599            let bincode_deserialized: BorrowedBytes = bincode::deserialize(&bincode_serialized).unwrap();
2600            let schema_deserialized: BorrowedBytes = deserialize(&schema_serialized).unwrap();
2601            prop_assert_eq!(&val, &bincode_deserialized);
2602            prop_assert_eq!(val, schema_deserialized);
2603        });
2604    }
2605
2606    #[test]
2607    fn test_boxed_slice_pod_drop() {
2608        #[derive(proptest_derive::Arbitrary, Debug, Clone, Copy)]
2609        #[allow(dead_code)]
2610        struct Signature([u8; 64]);
2611
2612        pod_wrapper! {
2613            unsafe struct PodSignature(Signature);
2614        }
2615
2616        type Target = containers::Box<[PodSignature], BincodeLen>;
2617        proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<Signature>(), 1..=32).prop_map(|vec| vec.into_boxed_slice()))| {
2618            let serialized = Target::serialize(&slice).unwrap();
2619            // Deliberately trigger the drop with a failed deserialization
2620            // This test is specifically to get miri to exercise the drop logic
2621            let deserialized = Target::deserialize(&serialized[..serialized.len() - 32]);
2622            prop_assert!(deserialized.is_err());
2623        });
2624    }
2625
2626    #[test]
2627    fn test_zero_copy_padding_disqualification() {
2628        #[derive(SchemaWrite, SchemaRead)]
2629        #[wincode(internal)]
2630        #[repr(C, align(4))]
2631        struct Padded {
2632            a: u8,
2633        }
2634
2635        assert!(matches!(
2636            <Padded as SchemaWrite<DefaultConfig>>::TYPE_META,
2637            TypeMeta::Static {
2638                // Serialized size is still the size of the byte, not the in-memory size.
2639                size: 1,
2640                // Padding disqualifies the type from zero-copy optimization.
2641                zero_copy: false
2642            }
2643        ));
2644
2645        assert!(matches!(
2646            <Padded as SchemaRead<'_, DefaultConfig>>::TYPE_META,
2647            TypeMeta::Static {
2648                // Serialized size is still the size of the byte, not the in-memory size.
2649                size: 1,
2650                // Padding disqualifies the type from zero-copy optimization.
2651                zero_copy: false
2652            }
2653        ));
2654    }
2655
2656    proptest! {
2657        #![proptest_config(proptest_cfg())]
2658
2659        #[test]
2660        fn test_char(val in any::<char>()) {
2661            let bincode_serialized = bincode::serialize(&val).unwrap();
2662            let schema_serialized = serialize(&val).unwrap();
2663            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2664            prop_assert_eq!(<char as SchemaWrite<DefaultConfig>>::size_of(&val).unwrap(), bincode::serialized_size(&val).unwrap() as usize);
2665
2666            let bincode_deserialized: char = bincode::deserialize(&bincode_serialized).unwrap();
2667            let schema_deserialized: char = deserialize(&schema_serialized).unwrap();
2668            prop_assert_eq!(val, bincode_deserialized);
2669            prop_assert_eq!(val, schema_deserialized);
2670        }
2671
2672        #[test]
2673        fn test_vec_elem_static(vec in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
2674            let bincode_serialized = bincode::serialize(&vec).unwrap();
2675            let schema_serialized = serialize(&vec).unwrap();
2676            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2677
2678            let bincode_deserialized: Vec<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
2679            let schema_deserialized: Vec<StructStatic> = deserialize(&schema_serialized).unwrap();
2680            prop_assert_eq!(&vec, &bincode_deserialized);
2681            prop_assert_eq!(vec, schema_deserialized);
2682        }
2683
2684        #[test]
2685        fn test_vec_elem_zero_copy(vec in proptest::collection::vec(any::<StructZeroCopy>(), 0..=100)) {
2686            let bincode_serialized = bincode::serialize(&vec).unwrap();
2687            let schema_serialized = serialize(&vec).unwrap();
2688            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2689
2690            let bincode_deserialized: Vec<StructZeroCopy> = bincode::deserialize(&bincode_serialized).unwrap();
2691            let schema_deserialized: Vec<StructZeroCopy> = deserialize(&schema_serialized).unwrap();
2692            prop_assert_eq!(&vec, &bincode_deserialized);
2693            prop_assert_eq!(vec, schema_deserialized);
2694        }
2695
2696        #[test]
2697        fn test_vec_elem_non_static(vec in proptest::collection::vec(any::<StructNonStatic>(), 0..=16)) {
2698            let bincode_serialized = bincode::serialize(&vec).unwrap();
2699            let schema_serialized = serialize(&vec).unwrap();
2700            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2701
2702            let bincode_deserialized: Vec<StructNonStatic> = bincode::deserialize(&bincode_serialized).unwrap();
2703            let schema_deserialized: Vec<StructNonStatic> = deserialize(&schema_serialized).unwrap();
2704            prop_assert_eq!(&vec, &bincode_deserialized);
2705            prop_assert_eq!(vec, schema_deserialized);
2706        }
2707
2708        #[test]
2709        fn test_vec_elem_bytes(vec in proptest::collection::vec(any::<u8>(), 0..=100)) {
2710            let bincode_serialized = bincode::serialize(&vec).unwrap();
2711            let schema_serialized = serialize(&vec).unwrap();
2712            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2713
2714            let bincode_deserialized: Vec<u8> = bincode::deserialize(&bincode_serialized).unwrap();
2715            let schema_deserialized: Vec<u8> = deserialize(&schema_serialized).unwrap();
2716            prop_assert_eq!(&vec, &bincode_deserialized);
2717            prop_assert_eq!(vec, schema_deserialized);
2718        }
2719
2720        #[test]
2721        fn test_serialize_slice(slice in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
2722            let bincode_serialized = bincode::serialize(slice.as_slice()).unwrap();
2723            let schema_serialized = serialize(slice.as_slice()).unwrap();
2724            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2725        }
2726
2727        #[test]
2728        fn test_vec_pod(vec in proptest::collection::vec(any::<[u8; 32]>(), 0..=100)) {
2729            let bincode_serialized = bincode::serialize(&vec).unwrap();
2730            let schema_serialized = serialize(&vec).unwrap();
2731            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2732
2733            let bincode_deserialized: Vec<[u8; 32]> = bincode::deserialize(&bincode_serialized).unwrap();
2734            let schema_deserialized: Vec<[u8; 32]> = deserialize(&schema_serialized).unwrap();
2735            prop_assert_eq!(&vec, &bincode_deserialized);
2736            prop_assert_eq!(vec, schema_deserialized);
2737        }
2738
2739        #[test]
2740        fn test_vec_deque_elem_static(vec in proptest::collection::vec_deque(any::<StructStatic>(), 0..=100)) {
2741            let bincode_serialized = bincode::serialize(&vec).unwrap();
2742            let schema_serialized = serialize(&vec).unwrap();
2743            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2744
2745            let bincode_deserialized: VecDeque<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
2746            let schema_deserialized: VecDeque<StructStatic> = deserialize(&schema_serialized).unwrap();
2747            prop_assert_eq!(&vec, &bincode_deserialized);
2748            prop_assert_eq!(vec, schema_deserialized);
2749        }
2750
2751        #[test]
2752        fn test_vec_deque_elem_non_static(vec in proptest::collection::vec_deque(any::<StructNonStatic>(), 0..=16)) {
2753            let bincode_serialized = bincode::serialize(&vec).unwrap();
2754            let schema_serialized = serialize(&vec).unwrap();
2755            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2756
2757            let bincode_deserialized: VecDeque<StructNonStatic> = bincode::deserialize(&bincode_serialized).unwrap();
2758            let schema_deserialized: VecDeque<StructNonStatic> = deserialize(&schema_serialized).unwrap();
2759            prop_assert_eq!(&vec, &bincode_deserialized);
2760            prop_assert_eq!(vec, schema_deserialized);
2761        }
2762
2763        #[test]
2764        fn test_vec_deque_elem_bytes(vec in proptest::collection::vec_deque(any::<u8>(), 0..=100)) {
2765            let bincode_serialized = bincode::serialize(&vec).unwrap();
2766            let schema_serialized = serialize(&vec).unwrap();
2767            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2768
2769            let bincode_deserialized: VecDeque<u8> = bincode::deserialize(&bincode_serialized).unwrap();
2770            let schema_deserialized: VecDeque<u8> = deserialize(&schema_serialized).unwrap();
2771            prop_assert_eq!(&vec, &bincode_deserialized);
2772            prop_assert_eq!(vec, schema_deserialized);
2773        }
2774
2775        #[test]
2776        fn test_hash_map_zero_copy(map in proptest::collection::hash_map(any::<u8>(), any::<StructZeroCopy>(), 0..=100)) {
2777            let bincode_serialized = bincode::serialize(&map).unwrap();
2778            let schema_serialized = serialize(&map).unwrap();
2779            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2780
2781            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2782            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2783            prop_assert_eq!(&map, &bincode_deserialized);
2784            prop_assert_eq!(map, schema_deserialized);
2785        }
2786
2787        #[test]
2788        fn test_hash_map_static(map in proptest::collection::hash_map(any::<u64>(), any::<StructStatic>(), 0..=100)) {
2789            let bincode_serialized = bincode::serialize(&map).unwrap();
2790            let schema_serialized = serialize(&map).unwrap();
2791            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2792
2793            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2794            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2795            prop_assert_eq!(&map, &bincode_deserialized);
2796            prop_assert_eq!(map, schema_deserialized);
2797        }
2798
2799        #[test]
2800        fn test_hash_map_non_static(map in proptest::collection::hash_map(any::<u64>(), any::<StructNonStatic>(), 0..=16)) {
2801            let bincode_serialized = bincode::serialize(&map).unwrap();
2802            let schema_serialized = serialize(&map).unwrap();
2803            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2804
2805            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2806            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2807            prop_assert_eq!(&map, &bincode_deserialized);
2808            prop_assert_eq!(map, schema_deserialized);
2809        }
2810
2811        #[test]
2812        fn test_hash_set_zero_copy(set in proptest::collection::hash_set(any::<StructZeroCopy>(), 0..=100)) {
2813            let bincode_serialized = bincode::serialize(&set).unwrap();
2814            let schema_serialized = serialize(&set).unwrap();
2815            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2816
2817            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2818            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2819            prop_assert_eq!(&set, &bincode_deserialized);
2820            prop_assert_eq!(set, schema_deserialized);
2821        }
2822
2823        #[test]
2824        fn test_hash_set_static(set in proptest::collection::hash_set(any::<StructStatic>(), 0..=100)) {
2825            let bincode_serialized = bincode::serialize(&set).unwrap();
2826            let schema_serialized = serialize(&set).unwrap();
2827            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2828
2829            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2830            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2831            prop_assert_eq!(&set, &bincode_deserialized);
2832            prop_assert_eq!(set, schema_deserialized);
2833        }
2834
2835        #[test]
2836        fn test_hash_set_non_static(set in proptest::collection::hash_set(any::<StructNonStatic>(), 0..=16)) {
2837            let bincode_serialized = bincode::serialize(&set).unwrap();
2838            let schema_serialized = serialize(&set).unwrap();
2839            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2840
2841            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2842            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2843            prop_assert_eq!(&set, &bincode_deserialized);
2844            prop_assert_eq!(set, schema_deserialized);
2845        }
2846
2847        #[test]
2848        fn test_sequences_with_hasher(data in proptest::collection::hash_map(any::<String>(), any::<HashSet<u32>>(), 0..16)) {
2849            #[derive(Default)]
2850            struct SumHasher(u64);
2851
2852            impl BuildHasher for SumHasher {
2853                type Hasher = Self;
2854                fn build_hasher(&self) -> Self::Hasher {
2855                    Self(0)
2856                }
2857            }
2858            impl Hasher for SumHasher {
2859                fn finish(&self) -> u64 {
2860                    self.0
2861                }
2862
2863                fn write(&mut self, bytes: &[u8]) {
2864                    self.0 += bytes.iter().map(|b| *b as u64).sum::<u64>();
2865                }
2866            }
2867
2868            type TestMap = HashMap<String, HashSet<u32, SumHasher>, SumHasher>;
2869            let test_data: TestMap = data.into_iter().map(|(k, v)| (k, HashSet::from_iter(v.into_iter()))).collect();
2870            let wincode_serialized = serialize(&test_data).unwrap();
2871            let bincode_serialized = bincode::serialize(&test_data).unwrap();
2872            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
2873
2874            let wincode_deserialized: TestMap = deserialize(&wincode_serialized).unwrap();
2875            let bincode_deserialized: TestMap = bincode::deserialize(&bincode_serialized).unwrap();
2876            prop_assert_eq!(&test_data, &wincode_deserialized);
2877            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
2878
2879            type TestMapSeq = containers::FromIntoIterator<TestMap, BincodeLen>;
2880            let test_seq_serialized = TestMapSeq::serialize(&test_data).unwrap();
2881            assert_eq!(test_seq_serialized, wincode_serialized);
2882            let test_seq_deserialized = TestMapSeq::deserialize(&test_seq_serialized).unwrap();
2883            prop_assert_eq!(&test_data, &test_seq_deserialized);
2884
2885            type RegularMap = HashMap<String, HashSet<u32>>;
2886            let regular_deserialized: RegularMap = deserialize(&wincode_serialized).unwrap();
2887            let regular_serialized = serialize(&regular_deserialized).unwrap();
2888            let test_deserialized: TestMap = deserialize(&regular_serialized).unwrap();
2889            prop_assert_eq!(test_data, test_deserialized);
2890
2891            type RegularMapSeq = containers::FromIntoIterator<RegularMap, BincodeLen>;
2892            let regular_seq_serialized = RegularMapSeq::serialize(&regular_deserialized).unwrap();
2893            assert_eq!(regular_serialized, regular_seq_serialized);
2894            let regular_seq_deserialized = RegularMapSeq::deserialize(&regular_seq_serialized).unwrap();
2895            prop_assert_eq!(&regular_deserialized, &regular_seq_deserialized);
2896        }
2897
2898        #[test]
2899        fn test_btree_map_zero_copy(map in proptest::collection::btree_map(any::<u8>(), any::<StructZeroCopy>(), 0..=100)) {
2900            let bincode_serialized = bincode::serialize(&map).unwrap();
2901            let schema_serialized = serialize(&map).unwrap();
2902            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2903
2904            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2905            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2906            prop_assert_eq!(&map, &bincode_deserialized);
2907            prop_assert_eq!(map, schema_deserialized);
2908        }
2909
2910        #[test]
2911        fn test_btree_map_static(map in proptest::collection::btree_map(any::<u64>(), any::<StructStatic>(), 0..=100)) {
2912            let bincode_serialized = bincode::serialize(&map).unwrap();
2913            let schema_serialized = serialize(&map).unwrap();
2914            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2915
2916            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2917            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2918            prop_assert_eq!(&map, &bincode_deserialized);
2919            prop_assert_eq!(map, schema_deserialized);
2920        }
2921
2922        #[test]
2923        fn test_btree_map_non_static(map in proptest::collection::btree_map(any::<u64>(), any::<StructNonStatic>(), 0..=16)) {
2924            let bincode_serialized = bincode::serialize(&map).unwrap();
2925            let schema_serialized = serialize(&map).unwrap();
2926            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2927
2928            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2929            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2930            prop_assert_eq!(&map, &bincode_deserialized);
2931            prop_assert_eq!(map, schema_deserialized);
2932        }
2933
2934        #[test]
2935        fn test_btree_set_zero_copy(set in proptest::collection::btree_set(any::<StructZeroCopy>(), 0..=100)) {
2936            let bincode_serialized = bincode::serialize(&set).unwrap();
2937            let schema_serialized = serialize(&set).unwrap();
2938            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2939
2940            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2941            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2942            prop_assert_eq!(&set, &bincode_deserialized);
2943            prop_assert_eq!(set, schema_deserialized);
2944        }
2945
2946        #[test]
2947        fn test_btree_set_static(set in proptest::collection::btree_set(any::<StructStatic>(), 0..=100)) {
2948            let bincode_serialized = bincode::serialize(&set).unwrap();
2949            let schema_serialized = serialize(&set).unwrap();
2950            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2951
2952            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2953            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2954            prop_assert_eq!(&set, &bincode_deserialized);
2955            prop_assert_eq!(set, schema_deserialized);
2956        }
2957
2958        #[test]
2959        fn test_btree_set_non_static(map in proptest::collection::btree_set(any::<StructNonStatic>(), 0..=16)) {
2960            let bincode_serialized = bincode::serialize(&map).unwrap();
2961            let schema_serialized = serialize(&map).unwrap();
2962            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2963
2964            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2965            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2966            prop_assert_eq!(&map, &bincode_deserialized);
2967            prop_assert_eq!(map, schema_deserialized);
2968        }
2969
2970        #[test]
2971        fn test_binary_heap_zero_copy(heap in proptest::collection::binary_heap(any::<StructZeroCopy>(), 0..=100)) {
2972            let bincode_serialized = bincode::serialize(&heap).unwrap();
2973            let schema_serialized = serialize(&heap).unwrap();
2974            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2975
2976            let bincode_deserialized: BinaryHeap<StructZeroCopy> = bincode::deserialize(&bincode_serialized).unwrap();
2977            let schema_deserialized: BinaryHeap<StructZeroCopy> = deserialize(&schema_serialized).unwrap();
2978            prop_assert_eq!(heap.as_slice(), bincode_deserialized.as_slice());
2979            prop_assert_eq!(heap.as_slice(), schema_deserialized.as_slice());
2980        }
2981
2982        #[test]
2983        fn test_binary_heap_static(heap in proptest::collection::binary_heap(any::<StructStatic>(), 0..=100)) {
2984            let bincode_serialized = bincode::serialize(&heap).unwrap();
2985            let schema_serialized = serialize(&heap).unwrap();
2986            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2987
2988            let bincode_deserialized: BinaryHeap<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
2989            let schema_deserialized: BinaryHeap<StructStatic> = deserialize(&schema_serialized).unwrap();
2990            prop_assert_eq!(heap.as_slice(), bincode_deserialized.as_slice());
2991            prop_assert_eq!(heap.as_slice(), schema_deserialized.as_slice());
2992        }
2993
2994        #[test]
2995        fn test_binary_heap_non_static(heap in proptest::collection::binary_heap(any::<StructNonStatic>(), 0..=16)) {
2996            let bincode_serialized = bincode::serialize(&heap).unwrap();
2997            let schema_serialized = serialize(&heap).unwrap();
2998            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2999
3000            let bincode_deserialized: BinaryHeap<StructNonStatic> = bincode::deserialize(&bincode_serialized).unwrap();
3001            let schema_deserialized: BinaryHeap<StructNonStatic> = deserialize(&schema_serialized).unwrap();
3002            prop_assert_eq!(heap.as_slice(), bincode_deserialized.as_slice());
3003            prop_assert_eq!(heap.as_slice(), schema_deserialized.as_slice());
3004        }
3005
3006        #[test]
3007        fn test_linked_list_zero_copy(list in proptest::collection::linked_list(any::<StructZeroCopy>(), 0..=100)) {
3008            let bincode_serialized = bincode::serialize(&list).unwrap();
3009            let schema_serialized = serialize(&list).unwrap();
3010            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3011
3012            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
3013            let schema_deserialized = deserialize(&schema_serialized).unwrap();
3014            prop_assert_eq!(&list, &bincode_deserialized);
3015            prop_assert_eq!(list, schema_deserialized);
3016        }
3017
3018        #[test]
3019        fn test_linked_list_static(list in proptest::collection::linked_list(any::<StructStatic>(), 0..=100)) {
3020            let bincode_serialized = bincode::serialize(&list).unwrap();
3021            let schema_serialized = serialize(&list).unwrap();
3022            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3023
3024            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
3025            let schema_deserialized = deserialize(&schema_serialized).unwrap();
3026            prop_assert_eq!(&list, &bincode_deserialized);
3027            prop_assert_eq!(list, schema_deserialized);
3028        }
3029
3030        #[test]
3031        fn test_linked_list_non_static(list in proptest::collection::linked_list(any::<StructNonStatic>(), 0..=16)) {
3032            let bincode_serialized = bincode::serialize(&list).unwrap();
3033            let schema_serialized = serialize(&list).unwrap();
3034            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3035
3036            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
3037            let schema_deserialized = deserialize(&schema_serialized).unwrap();
3038            prop_assert_eq!(&list, &bincode_deserialized);
3039            prop_assert_eq!(list, schema_deserialized);
3040        }
3041
3042        #[test]
3043        fn test_array_bytes(array in any::<[u8; 32]>()) {
3044            let bincode_serialized = bincode::serialize(&array).unwrap();
3045            let schema_serialized = serialize(&array).unwrap();
3046            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3047
3048            let bincode_deserialized: [u8; 32] = bincode::deserialize(&bincode_serialized).unwrap();
3049            let schema_deserialized: [u8; 32] = deserialize(&schema_serialized).unwrap();
3050            prop_assert_eq!(&array, &bincode_deserialized);
3051            prop_assert_eq!(array, schema_deserialized);
3052        }
3053
3054        #[test]
3055        fn test_array_static(array in any::<[u64; 32]>()) {
3056            let bincode_serialized = bincode::serialize(&array).unwrap();
3057            type Target = [u64; 32];
3058            let schema_serialized = Target::serialize(&array).unwrap();
3059            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3060            let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
3061            let schema_deserialized: Target = deserialize(&schema_serialized).unwrap();
3062            prop_assert_eq!(&array, &bincode_deserialized);
3063            prop_assert_eq!(array, schema_deserialized);
3064        }
3065
3066        #[test]
3067        fn test_array_non_static(array in any::<[StructNonStatic; 16]>()) {
3068            let bincode_serialized = bincode::serialize(&array).unwrap();
3069            type Target = [StructNonStatic; 16];
3070            let schema_serialized = Target::serialize(&array).unwrap();
3071            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3072            let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
3073            let schema_deserialized: Target = deserialize(&schema_serialized).unwrap();
3074            prop_assert_eq!(&array, &bincode_deserialized);
3075            prop_assert_eq!(array, schema_deserialized);
3076        }
3077
3078        #[test]
3079        fn test_option(option in proptest::option::of(any::<StructStatic>())) {
3080            let bincode_serialized = bincode::serialize(&option).unwrap();
3081            let schema_serialized = serialize(&option).unwrap();
3082
3083            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3084            let bincode_deserialized: Option<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
3085            let schema_deserialized: Option<StructStatic> = deserialize(&schema_serialized).unwrap();
3086            prop_assert_eq!(&option, &bincode_deserialized);
3087            prop_assert_eq!(&option, &schema_deserialized);
3088        }
3089
3090        #[test]
3091        fn test_option_container(option in proptest::option::of(any::<[u8; 32]>())) {
3092            let bincode_serialized = bincode::serialize(&option).unwrap();
3093            type Target = Option<[u8; 32]>;
3094            let schema_serialized = Target::serialize(&option).unwrap();
3095            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3096            let bincode_deserialized: Option<[u8; 32]> = bincode::deserialize(&bincode_serialized).unwrap();
3097            let schema_deserialized: Option<[u8; 32]> = Target::deserialize(&schema_serialized).unwrap();
3098            prop_assert_eq!(&option, &bincode_deserialized);
3099            prop_assert_eq!(&option, &schema_deserialized);
3100        }
3101
3102        #[test]
3103        fn test_bool(val in any::<bool>()) {
3104            let bincode_serialized = bincode::serialize(&val).unwrap();
3105            let schema_serialized = serialize(&val).unwrap();
3106            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3107            let bincode_deserialized: bool = bincode::deserialize(&bincode_serialized).unwrap();
3108            let schema_deserialized: bool = deserialize(&schema_serialized).unwrap();
3109            prop_assert_eq!(val, bincode_deserialized);
3110            prop_assert_eq!(val, schema_deserialized);
3111        }
3112
3113        #[test]
3114        fn test_bool_invalid_bit_pattern(val in 2u8..=255) {
3115            let bincode_deserialized: Result<bool,_> = bincode::deserialize(&[val]);
3116            let schema_deserialized: Result<bool,_> = deserialize(&[val]);
3117            prop_assert!(bincode_deserialized.is_err());
3118            prop_assert!(schema_deserialized.is_err());
3119        }
3120
3121        #[test]
3122        fn test_box(s in any::<StructStatic>()) {
3123            let data = Box::new(s);
3124            let bincode_serialized = bincode::serialize(&data).unwrap();
3125            let schema_serialized = serialize(&data).unwrap();
3126            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3127
3128            let bincode_deserialized: Box<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
3129            let schema_deserialized: Box<StructStatic> = deserialize(&schema_serialized).unwrap();
3130            prop_assert_eq!(&data, &bincode_deserialized);
3131            prop_assert_eq!(&data, &schema_deserialized);
3132        }
3133
3134        #[test]
3135        fn test_rc(s in any::<StructStatic>()) {
3136            let data = Rc::new(s);
3137            let bincode_serialized = bincode::serialize(&data).unwrap();
3138            let schema_serialized = serialize(&data).unwrap();
3139            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3140
3141            let bincode_deserialized: Rc<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
3142            let schema_deserialized: Rc<StructStatic> = deserialize(&schema_serialized).unwrap();
3143            prop_assert_eq!(&data, &bincode_deserialized);
3144            prop_assert_eq!(&data, &schema_deserialized);
3145        }
3146
3147        #[test]
3148        fn test_arc(s in any::<StructStatic>()) {
3149            let data = Arc::new(s);
3150            let bincode_serialized = bincode::serialize(&data).unwrap();
3151            let schema_serialized = serialize(&data).unwrap();
3152            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3153
3154            let bincode_deserialized: Arc<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
3155            let schema_deserialized: Arc<StructStatic> = deserialize(&schema_serialized).unwrap();
3156            prop_assert_eq!(&data, &bincode_deserialized);
3157            prop_assert_eq!(&data, &schema_deserialized);
3158        }
3159
3160        #[test]
3161        fn test_boxed_slice_zero_copy(vec in proptest::collection::vec(any::<StructZeroCopy>(), 0..=100)) {
3162            let data = vec.into_boxed_slice();
3163            let bincode_serialized = bincode::serialize(&data).unwrap();
3164            let schema_serialized = serialize(&data).unwrap();
3165            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3166
3167            let bincode_deserialized: Box<[StructZeroCopy]> = bincode::deserialize(&bincode_serialized).unwrap();
3168            let schema_deserialized: Box<[StructZeroCopy]> = deserialize(&schema_serialized).unwrap();
3169            prop_assert_eq!(&data, &bincode_deserialized);
3170            prop_assert_eq!(&data, &schema_deserialized);
3171        }
3172
3173        #[test]
3174        fn test_boxed_slice_static(vec in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
3175            let data = vec.into_boxed_slice();
3176            let bincode_serialized = bincode::serialize(&data).unwrap();
3177            let schema_serialized = serialize(&data).unwrap();
3178            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3179
3180            let bincode_deserialized: Box<[StructStatic]> = bincode::deserialize(&bincode_serialized).unwrap();
3181            let schema_deserialized: Box<[StructStatic]> = deserialize(&schema_serialized).unwrap();
3182            prop_assert_eq!(&data, &bincode_deserialized);
3183            prop_assert_eq!(&data, &schema_deserialized);
3184        }
3185
3186        #[test]
3187        fn test_boxed_slice_non_static(vec in proptest::collection::vec(any::<StructNonStatic>(), 0..=16)) {
3188            let data = vec.into_boxed_slice();
3189            let bincode_serialized = bincode::serialize(&data).unwrap();
3190            type Target = Box<[StructNonStatic]>;
3191            let schema_serialized = serialize(&data).unwrap();
3192            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3193
3194            let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
3195            let schema_deserialized: Target = Target::deserialize(&schema_serialized).unwrap();
3196            prop_assert_eq!(&data, &bincode_deserialized);
3197            prop_assert_eq!(&data, &schema_deserialized);
3198        }
3199
3200        #[test]
3201        fn test_integers(
3202            val in (
3203                any::<u8>(),
3204                any::<i8>(),
3205                any::<u16>(),
3206                any::<i16>(),
3207                any::<u32>(),
3208                any::<i32>(),
3209                any::<usize>(),
3210                any::<isize>(),
3211                any::<u64>(),
3212                any::<i64>(),
3213                any::<u128>(),
3214                any::<i128>()
3215            )
3216        ) {
3217            type Target = (u8, i8, u16, i16, u32, i32, usize, isize, u64, i64, u128, i128);
3218            let bincode_serialized = bincode::serialize(&val).unwrap();
3219            let schema_serialized = serialize(&val).unwrap();
3220            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3221            let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
3222            let schema_deserialized: Target = deserialize(&schema_serialized).unwrap();
3223            prop_assert_eq!(val, bincode_deserialized);
3224            prop_assert_eq!(val, schema_deserialized);
3225        }
3226
3227        #[test]
3228        fn test_tuple_zero_copy(
3229            tuple in (
3230                any::<StructZeroCopy>(),
3231                any::<[u8; 32]>(),
3232            )
3233        ) {
3234            let bincode_serialized = bincode::serialize(&tuple).unwrap();
3235            let schema_serialized = serialize(&tuple).unwrap();
3236
3237            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3238            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
3239            let schema_deserialized = deserialize(&schema_serialized).unwrap();
3240            prop_assert_eq!(&tuple, &bincode_deserialized);
3241            prop_assert_eq!(&tuple, &schema_deserialized);
3242
3243        }
3244
3245        #[test]
3246        fn test_single_element_tuple(value in any::<u8>()) {
3247            let tuple = (value,);
3248            let bincode_serialized = bincode::serialize(&tuple).unwrap();
3249            let schema_serialized = serialize(&tuple).unwrap();
3250
3251            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3252            let bincode_deserialized: (u8,) = bincode::deserialize(&bincode_serialized).unwrap();
3253            let schema_deserialized: (u8,) = deserialize(&schema_serialized).unwrap();
3254            prop_assert_eq!(tuple, bincode_deserialized);
3255            prop_assert_eq!(tuple, schema_deserialized);
3256        }
3257
3258        #[test]
3259        fn test_tuple_static(
3260            tuple in (
3261                any::<StructStatic>(),
3262                any::<[u8; 32]>(),
3263            )
3264        ) {
3265            let bincode_serialized = bincode::serialize(&tuple).unwrap();
3266            let schema_serialized = serialize(&tuple).unwrap();
3267
3268            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3269            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
3270            let schema_deserialized = deserialize(&schema_serialized).unwrap();
3271            prop_assert_eq!(&tuple, &bincode_deserialized);
3272            prop_assert_eq!(&tuple, &schema_deserialized);
3273
3274        }
3275
3276        #[test]
3277        fn test_tuple_non_static(
3278            tuple in (
3279                any::<StructNonStatic>(),
3280                any::<[u8; 32]>(),
3281                proptest::collection::vec(any::<StructStatic>(), 0..=100),
3282            )
3283        ) {
3284            let bincode_serialized = bincode::serialize(&tuple).unwrap();
3285            type BincodeTarget = (StructNonStatic, [u8; 32], Vec<StructStatic>);
3286            type Target = (StructNonStatic, [u8; 32], Vec<StructStatic>);
3287            let schema_serialized = Target::serialize(&tuple).unwrap();
3288
3289            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3290            let bincode_deserialized: BincodeTarget = bincode::deserialize(&bincode_serialized).unwrap();
3291            let schema_deserialized = Target::deserialize(&schema_serialized).unwrap();
3292            prop_assert_eq!(&tuple, &bincode_deserialized);
3293            prop_assert_eq!(&tuple, &schema_deserialized);
3294
3295        }
3296
3297        #[test]
3298        fn test_str(str in any::<String>()) {
3299            let bincode_serialized = bincode::serialize(&str).unwrap();
3300            let schema_serialized = serialize(&str).unwrap();
3301            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3302            let bincode_deserialized: &str = bincode::deserialize(&bincode_serialized).unwrap();
3303            let schema_deserialized: &str = deserialize(&schema_serialized).unwrap();
3304            prop_assert_eq!(&str, &bincode_deserialized);
3305            prop_assert_eq!(&str, &schema_deserialized);
3306
3307            let bincode_deserialized: String = bincode::deserialize(&bincode_serialized).unwrap();
3308            let schema_deserialized: String = deserialize(&schema_serialized).unwrap();
3309            prop_assert_eq!(&str, &bincode_deserialized);
3310            prop_assert_eq!(&str, &schema_deserialized);
3311        }
3312
3313        #[test]
3314        fn test_struct_zero_copy(val in any::<StructZeroCopy>()) {
3315            let bincode_serialized = bincode::serialize(&val).unwrap();
3316            let schema_serialized = serialize(&val).unwrap();
3317            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3318
3319            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
3320            let schema_deserialized = deserialize(&schema_serialized).unwrap();
3321            prop_assert_eq!(&val, &bincode_deserialized);
3322            prop_assert_eq!(&val, &schema_deserialized);
3323        }
3324
3325        #[test]
3326        fn test_struct_static(val in any::<StructStatic>()) {
3327            let bincode_serialized = bincode::serialize(&val).unwrap();
3328            let schema_serialized = serialize(&val).unwrap();
3329            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3330
3331            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
3332            let schema_deserialized = deserialize(&schema_serialized).unwrap();
3333            prop_assert_eq!(&val, &bincode_deserialized);
3334            prop_assert_eq!(&val, &schema_deserialized);
3335        }
3336
3337        #[test]
3338        fn test_struct_non_static(val in any::<StructNonStatic>()) {
3339            let bincode_serialized = bincode::serialize(&val).unwrap();
3340            let schema_serialized = serialize(&val).unwrap();
3341            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3342
3343            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
3344            let schema_deserialized = deserialize(&schema_serialized).unwrap();
3345            prop_assert_eq!(&val, &bincode_deserialized);
3346            prop_assert_eq!(&val, &schema_deserialized);
3347        }
3348
3349        #[test]
3350        fn test_floats(
3351            val in (
3352                any::<f32>(),
3353                any::<f64>(),
3354            )
3355        ) {
3356            let bincode_serialized = bincode::serialize(&val).unwrap();
3357            let schema_serialized = serialize(&val).unwrap();
3358            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3359
3360            let bincode_deserialized: (f32, f64) = bincode::deserialize(&bincode_serialized).unwrap();
3361            let schema_deserialized: (f32, f64) = deserialize(&schema_serialized).unwrap();
3362            prop_assert_eq!(val, bincode_deserialized);
3363            prop_assert_eq!(val, schema_deserialized);
3364        }
3365    }
3366
3367    #[test]
3368    fn test_struct_zero_copy_refs() {
3369        // Owned zero-copy type.
3370        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
3371        #[wincode(internal)]
3372        #[repr(C)]
3373        struct Zc {
3374            a: u8,
3375            b: [u8; 64],
3376            c: i8,
3377            d: [i8; 64],
3378        }
3379
3380        // `Zc`, mirrored with references.
3381        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
3382        #[wincode(internal)]
3383        #[repr(C)]
3384        struct ZcRefs<'a> {
3385            a: &'a u8,
3386            b: &'a [u8; 64],
3387            c: &'a i8,
3388            d: &'a [i8; 64],
3389        }
3390
3391        // `Zc`, wrapped in a reference.
3392        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
3393        #[wincode(internal)]
3394        #[repr(transparent)]
3395        struct ZcWrapper<'a> {
3396            data: &'a Zc,
3397        }
3398
3399        impl<'a> From<&'a ZcRefs<'a>> for Zc {
3400            fn from(value: &'a ZcRefs<'a>) -> Self {
3401                Self {
3402                    a: *value.a,
3403                    b: *value.b,
3404                    c: *value.c,
3405                    d: *value.d,
3406                }
3407            }
3408        }
3409
3410        proptest!(proptest_cfg(), |(data in any::<Zc>())| {
3411            let serialized = serialize(&data).unwrap();
3412            let deserialized = Zc::deserialize(&serialized).unwrap();
3413            assert_eq!(data, deserialized);
3414
3415            let serialized_ref = serialize(&ZcRefs { a: &data.a, b: &data.b, c: &data.c, d: &data.d }).unwrap();
3416            assert_eq!(serialized_ref, serialized);
3417            let deserialized_ref = ZcRefs::deserialize(&serialized_ref).unwrap();
3418            assert_eq!(data, (&deserialized_ref).into());
3419
3420            let serialized_wrapper = serialize(&ZcWrapper { data: &data }).unwrap();
3421            assert_eq!(serialized_wrapper, serialized);
3422            let deserialized_wrapper = ZcWrapper::deserialize(&serialized_wrapper).unwrap();
3423            assert_eq!(data, *deserialized_wrapper.data);
3424        });
3425    }
3426
3427    #[test]
3428    fn test_zero_copy_ref_with_integer_types() {
3429        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
3430        #[wincode(internal)]
3431        struct ZcRef<'a> {
3432            x: &'a StructZeroCopy,
3433        }
3434
3435        proptest!(proptest_cfg(), |(data in any::<StructZeroCopy>())| {
3436            let serialized = serialize_aligned(&data).unwrap();
3437            let deserialized: ZcRef<'_> = deserialize(&serialized).unwrap();
3438            assert_eq!(data, *deserialized.x);
3439        });
3440    }
3441
3442    #[test]
3443    fn test_zero_copy_enum_with_integer_types() {
3444        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
3445        #[wincode(internal)]
3446        #[wincode(tag_encoding = "u128")]
3447        enum Enum {
3448            A,
3449            B(StructZeroCopy),
3450        }
3451
3452        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
3453        #[wincode(internal)]
3454        #[wincode(tag_encoding = "u128")]
3455        enum EnumRef<'a> {
3456            A,
3457            B(&'a StructZeroCopy),
3458        }
3459
3460        proptest!(proptest_cfg(), |(data in any::<Enum>())| {
3461            let serialized = serialize_aligned(&data).unwrap();
3462            let deserialized: EnumRef<'_> = deserialize(&serialized).unwrap();
3463            match data {
3464                Enum::A => prop_assert!(matches!(deserialized, EnumRef::A)),
3465                Enum::B(x) => prop_assert!(matches!(deserialized, EnumRef::B(y) if &x == y)),
3466            }
3467        });
3468    }
3469
3470    #[test]
3471    fn test_empty_struct() {
3472        #[derive(
3473            Debug,
3474            SchemaWrite,
3475            SchemaRead,
3476            Default,
3477            PartialEq,
3478            Eq,
3479            serde::Serialize,
3480            serde::Deserialize,
3481        )]
3482        #[wincode(internal)]
3483        struct EmptyStruct {}
3484
3485        let empty = EmptyStruct::default();
3486
3487        let bincode_serialized = bincode::serialize(&empty).unwrap();
3488        let schema_serialized = serialize(&empty).unwrap();
3489
3490        // Empty structs should serialize to zero bytes
3491        assert_eq!(bincode_serialized, schema_serialized);
3492        assert_eq!(bincode_serialized.len(), 0);
3493
3494        let bincode_deserialized: EmptyStruct = bincode::deserialize(&bincode_serialized).unwrap();
3495        let schema_deserialized: EmptyStruct = deserialize(&schema_serialized).unwrap();
3496
3497        assert_eq!(empty, bincode_deserialized);
3498        assert_eq!(empty, schema_deserialized);
3499    }
3500
3501    #[test]
3502    fn test_pod_zero_copy() {
3503        #[derive(Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy)]
3504        #[repr(transparent)]
3505        struct Address([u8; 64]);
3506
3507        pod_wrapper! {
3508            unsafe struct PodAddress(Address);
3509        }
3510
3511        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
3512        #[wincode(internal)]
3513        #[repr(C)]
3514        struct MyStruct {
3515            #[wincode(with = "PodAddress")]
3516            address: Address,
3517        }
3518
3519        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
3520        #[wincode(internal)]
3521        struct MyStructRef<'a> {
3522            inner: &'a MyStruct,
3523        }
3524
3525        proptest!(proptest_cfg(), |(data in any::<MyStruct>())| {
3526            let serialized = serialize(&data).unwrap();
3527            let deserialized = MyStruct::deserialize(&serialized).unwrap();
3528            assert_eq!(data, deserialized);
3529
3530            let serialized_ref = serialize(&MyStructRef { inner: &data }).unwrap();
3531            assert_eq!(serialized_ref, serialized);
3532            let deserialized_ref = MyStructRef::deserialize(&serialized_ref).unwrap();
3533            assert_eq!(data, *deserialized_ref.inner);
3534        });
3535    }
3536
3537    #[test]
3538    fn test_pod_zero_copy_explicit_ref() {
3539        #[derive(Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy)]
3540        #[repr(transparent)]
3541        struct Address([u8; 64]);
3542
3543        pod_wrapper! {
3544            unsafe struct PodAddress(Address);
3545        }
3546
3547        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
3548        #[wincode(internal)]
3549        struct MyStructRef<'a> {
3550            #[wincode(with = "&'a PodAddress")]
3551            address: &'a Address,
3552        }
3553
3554        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
3555        #[wincode(internal)]
3556        struct MyStruct {
3557            #[wincode(with = "PodAddress")]
3558            address: Address,
3559        }
3560
3561        proptest!(proptest_cfg(), |(data in any::<MyStruct>())| {
3562            let serialized = serialize(&data).unwrap();
3563            let deserialized = MyStruct::deserialize(&serialized).unwrap();
3564            assert_eq!(data, deserialized);
3565
3566            let serialized_ref = serialize(&MyStructRef { address: &data.address }).unwrap();
3567            assert_eq!(serialized_ref, serialized);
3568            let deserialized_ref = MyStructRef::deserialize(&serialized_ref).unwrap();
3569            assert_eq!(data.address, *deserialized_ref.address);
3570        });
3571    }
3572
3573    #[test]
3574    fn test_read_adapter_lifetime_is_rewritten_to_de() {
3575        #[derive(Debug, PartialEq, Eq)]
3576        struct MyType<'a, T>(&'a [u8; 4], PhantomData<T>);
3577
3578        struct MyOtherType<'a, T>(PhantomData<(&'a (), T)>);
3579
3580        unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for MyOtherType<'de, T> {
3581            type Dst = MyType<'de, T>;
3582
3583            fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
3584                let value = <&'de [u8; 4] as SchemaRead<'de, C>>::get(reader)?;
3585                dst.write(MyType(value, PhantomData));
3586                Ok(())
3587            }
3588        }
3589
3590        #[derive(SchemaRead, Debug, PartialEq, Eq)]
3591        #[wincode(internal)]
3592        struct Foo<'a, T> {
3593            #[wincode(with = "MyOtherType<'a, T>")]
3594            x: MyType<'a, T>,
3595        }
3596
3597        let foo = <Foo<'_, ()> as SchemaRead<'_, DefaultConfig>>::get(&[1, 2, 3, 4][..]).unwrap();
3598        assert_eq!(foo.x, MyType(&[1, 2, 3, 4], PhantomData));
3599    }
3600
3601    #[test]
3602    fn test_result_basic() {
3603        proptest!(proptest_cfg(), |(value: Result<u64, String>)| {
3604            let wincode_serialized = serialize(&value).unwrap();
3605            let bincode_serialized = bincode::serialize(&value).unwrap();
3606            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
3607
3608            let wincode_deserialized: Result<u64, String> = deserialize(&wincode_serialized).unwrap();
3609            let bincode_deserialized: Result<u64, String> = bincode::deserialize(&bincode_serialized).unwrap();
3610            prop_assert_eq!(&value, &wincode_deserialized);
3611            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
3612        });
3613    }
3614
3615    #[test]
3616    fn test_result_bincode_equivalence() {
3617        use serde::{Deserialize, Serialize};
3618
3619        #[derive(
3620            Serialize,
3621            Deserialize,
3622            Debug,
3623            PartialEq,
3624            Clone,
3625            proptest_derive::Arbitrary,
3626            SchemaWrite,
3627            SchemaRead,
3628        )]
3629        #[wincode(internal)]
3630        enum Error {
3631            NotFound,
3632            InvalidInput(String),
3633            Other(u32),
3634        }
3635
3636        proptest!(proptest_cfg(), |(value: Result<Vec<u8>, Error>)| {
3637            let wincode_serialized = serialize(&value).unwrap();
3638            let bincode_serialized = bincode::serialize(&value).unwrap();
3639            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
3640
3641            let wincode_deserialized: Result<Vec<u8>, Error> = deserialize(&wincode_serialized).unwrap();
3642            let bincode_deserialized: Result<Vec<u8>, Error> = bincode::deserialize(&bincode_serialized).unwrap();
3643            prop_assert_eq!(&value, &wincode_deserialized);
3644            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
3645        });
3646    }
3647
3648    #[test]
3649    fn test_result_nested() {
3650        proptest!(proptest_cfg(), |(value: Result<Result<u64, String>, u32>)| {
3651            let wincode_serialized = serialize(&value).unwrap();
3652            let bincode_serialized = bincode::serialize(&value).unwrap();
3653            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
3654
3655            let wincode_deserialized: Result<Result<u64, String>, u32> = deserialize(&wincode_serialized).unwrap();
3656            let bincode_deserialized: Result<Result<u64, String>, u32> = bincode::deserialize(&bincode_serialized).unwrap();
3657            prop_assert_eq!(&value, &wincode_deserialized);
3658            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
3659        });
3660    }
3661
3662    #[test]
3663    fn test_result_with_complex_types() {
3664        use std::collections::HashMap;
3665
3666        proptest!(proptest_cfg(), |(value: Result<HashMap<String, Vec<u32>>, bool>)| {
3667            let wincode_serialized = serialize(&value).unwrap();
3668            let bincode_serialized = bincode::serialize(&value).unwrap();
3669            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
3670
3671            let wincode_deserialized: Result<HashMap<String, Vec<u32>>, bool> = deserialize(&wincode_serialized).unwrap();
3672            let bincode_deserialized: Result<HashMap<String, Vec<u32>>, bool> = bincode::deserialize(&bincode_serialized).unwrap();
3673            prop_assert_eq!(&value, &wincode_deserialized);
3674            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
3675        });
3676    }
3677
3678    #[test]
3679    fn test_result_type_meta_static() {
3680        // Result<u64, u64> should be TypeMeta::Static because both T and E are Static with equal sizes
3681        assert!(matches!(
3682            <Result<u64, u64> as SchemaRead<DefaultConfig>>::TYPE_META,
3683            TypeMeta::Static {
3684                size: 12,
3685                zero_copy: false
3686            }
3687        ));
3688
3689        proptest!(proptest_cfg(), |(value: Result<u64, u64>)| {
3690            let wincode_serialized = serialize(&value).unwrap();
3691            let bincode_serialized = bincode::serialize(&value).unwrap();
3692            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
3693
3694            let wincode_deserialized: Result<u64, u64> = deserialize(&wincode_serialized).unwrap();
3695            let bincode_deserialized: Result<u64, u64> = bincode::deserialize(&bincode_serialized).unwrap();
3696            prop_assert_eq!(&value, &wincode_deserialized);
3697            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
3698        });
3699    }
3700
3701    #[test]
3702    fn test_result_type_meta_dynamic() {
3703        // Result<u64, String> should be TypeMeta::Dynamic because String is Dynamic
3704        assert!(matches!(
3705            <Result<u64, String> as SchemaRead<DefaultConfig>>::TYPE_META,
3706            TypeMeta::Dynamic
3707        ));
3708
3709        proptest!(proptest_cfg(), |(value: Result<u64, String>)| {
3710            let wincode_serialized = serialize(&value).unwrap();
3711            let bincode_serialized = bincode::serialize(&value).unwrap();
3712            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
3713
3714            let wincode_deserialized: Result<u64, String> = deserialize(&wincode_serialized).unwrap();
3715            let bincode_deserialized: Result<u64, String> = bincode::deserialize(&bincode_serialized).unwrap();
3716            prop_assert_eq!(&value, &wincode_deserialized);
3717            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
3718        });
3719    }
3720
3721    #[test]
3722    fn test_result_type_meta_different_sizes() {
3723        // Result<u64, u32> should be TypeMeta::Dynamic because T and E have different sizes
3724        assert!(matches!(
3725            <Result<u64, u32> as SchemaRead<DefaultConfig>>::TYPE_META,
3726            TypeMeta::Dynamic
3727        ));
3728
3729        proptest!(proptest_cfg(), |(value: Result<u64, u32>)| {
3730            let wincode_serialized = serialize(&value).unwrap();
3731            let bincode_serialized = bincode::serialize(&value).unwrap();
3732            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
3733
3734            let wincode_deserialized: Result<u64, u32> = deserialize(&wincode_serialized).unwrap();
3735            let bincode_deserialized: Result<u64, u32> = bincode::deserialize(&bincode_serialized).unwrap();
3736            prop_assert_eq!(&value, &wincode_deserialized);
3737            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
3738        });
3739    }
3740
3741    /// A buffer containing a single instance of type `T`,
3742    /// aligned for `T`.
3743    ///
3744    /// Implements [`Deref`] and [`DerefMut`] for `[u8]` such that it
3745    /// acts like a typical byte buffer, but aligned for `T`.
3746    struct BufAligned {
3747        buf: *mut u8,
3748        layout: Layout,
3749    }
3750
3751    impl Deref for BufAligned {
3752        type Target = [u8];
3753
3754        fn deref(&self) -> &Self::Target {
3755            unsafe { core::slice::from_raw_parts(self.buf as *const u8, self.layout.size()) }
3756        }
3757    }
3758
3759    impl DerefMut for BufAligned {
3760        fn deref_mut(&mut self) -> &mut Self::Target {
3761            unsafe { core::slice::from_raw_parts_mut(self.buf, self.layout.size()) }
3762        }
3763    }
3764
3765    impl Drop for BufAligned {
3766        fn drop(&mut self) {
3767            use alloc::alloc::dealloc;
3768            unsafe { dealloc(self.buf, self.layout) }
3769        }
3770    }
3771
3772    /// Serialize a single instance of type `T` into a buffer aligned for `T`.
3773    fn serialize_aligned<T>(src: &T) -> WriteResult<BufAligned>
3774    where
3775        T: SchemaWrite<DefaultConfig, Src = T>,
3776    {
3777        use alloc::alloc::alloc;
3778        let size = T::size_of(src)?;
3779        let layout = Layout::from_size_align(size, align_of::<T>()).unwrap();
3780        let mem = unsafe { alloc(layout) };
3781        if mem.is_null() {
3782            return Err(crate::WriteError::Custom("could not allocate"));
3783        }
3784        let mut buf = BufAligned { buf: mem, layout };
3785        crate::serialize_into(buf.deref_mut(), src)?;
3786        Ok(buf)
3787    }
3788
3789    #[test]
3790    fn test_zero_copy_mut_roundrip() {
3791        proptest!(proptest_cfg(), |(data: StructZeroCopy, data_rand: StructZeroCopy)| {
3792            let mut serialized = serialize_aligned(&data).unwrap();
3793            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
3794            prop_assert_eq!(deserialized, data);
3795
3796
3797            // Mutate the serialized data in place
3798            {
3799                let ref_mut = StructZeroCopy::from_bytes_mut(&mut serialized).unwrap();
3800                *ref_mut = data_rand;
3801            }
3802            // Deserialize again on the same serialized data to
3803            // verify the changes were persisted
3804            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
3805            prop_assert_eq!(deserialized, data_rand);
3806        });
3807    }
3808
3809    #[test]
3810    fn test_deserialize_mut_roundrip() {
3811        proptest!(proptest_cfg(), |(data: StructZeroCopy, data_rand: StructZeroCopy)| {
3812            let mut serialized = serialize_aligned(&data).unwrap();
3813            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
3814            prop_assert_eq!(deserialized, data);
3815
3816
3817            // Mutate the serialized data in place
3818            {
3819                let ref_mut: &mut StructZeroCopy = deserialize_mut(&mut serialized).unwrap();
3820                *ref_mut = data_rand;
3821            }
3822            // Deserialize again on the same serialized data to
3823            // verify the changes were persisted
3824            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
3825            prop_assert_eq!(deserialized, data_rand);
3826        });
3827    }
3828
3829    #[test]
3830    fn test_zero_copy_deserialize_ref() {
3831        proptest!(proptest_cfg(), |(data: StructZeroCopy)| {
3832            let serialized = serialize_aligned(&data).unwrap();
3833            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
3834            prop_assert_eq!(deserialized, data);
3835
3836            let ref_data = StructZeroCopy::from_bytes(&serialized).unwrap();
3837            prop_assert_eq!(ref_data, &data);
3838        });
3839    }
3840
3841    #[test]
3842    fn test_custom_preallocation_size_limit() {
3843        let c = Configuration::default().with_preallocation_size_limit::<64>();
3844        proptest!(proptest_cfg(), |(value in proptest::collection::vec(any::<u8>(), 0..=128))| {
3845            let wincode_serialized = crate::serialize(&value).unwrap();
3846            let wincode_deserialized: Result<Vec<u8>, _> = config::deserialize(&wincode_serialized, c);
3847            if value.len() <= 64 {
3848                prop_assert_eq!(value, wincode_deserialized.unwrap());
3849            } else {
3850                prop_assert!(wincode_deserialized.is_err());
3851            }
3852        });
3853    }
3854
3855    #[test]
3856    fn test_preallocation_size_limit_rejects_zst_hashmap_len() {
3857        let c = Configuration::default().with_preallocation_size_limit::<4>();
3858        let serialized = 5u64.to_le_bytes();
3859        let decoded: Result<HashMap<(), ()>, _> = config::deserialize(&serialized, c);
3860        assert!(matches!(
3861            decoded,
3862            Err(ReadError::PreallocationSizeLimit {
3863                needed: 5,
3864                limit: 4
3865            })
3866        ));
3867    }
3868
3869    #[test]
3870    fn test_custom_length_encoding() {
3871        let c = Configuration::default().with_length_encoding::<FixIntLen<u32>>();
3872
3873        proptest!(proptest_cfg(), |(value: Vec<u8>)| {
3874            let wincode_serialized = config::serialize(&value, c).unwrap();
3875            let wincode_deserialized: Vec<u8> = config::deserialize(&wincode_serialized, c).unwrap();
3876            let len = value.len();
3877            prop_assert_eq!(len, u32::from_le_bytes(wincode_serialized[0..4].try_into().unwrap()) as usize);
3878            prop_assert_eq!(value, wincode_deserialized);
3879        });
3880    }
3881
3882    #[test]
3883    fn test_duration() {
3884        use core::time::Duration;
3885
3886        proptest!(proptest_cfg(), |(val: Duration)| {
3887            let bincode_serialized = bincode::serialize(&val).unwrap();
3888            let schema_serialized = serialize(&val).unwrap();
3889            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3890
3891            let bincode_deserialized: Duration = bincode::deserialize(&bincode_serialized).unwrap();
3892            let schema_deserialized: Duration = deserialize(&schema_serialized).unwrap();
3893            prop_assert_eq!(val, bincode_deserialized);
3894            prop_assert_eq!(val, schema_deserialized);
3895        });
3896    }
3897
3898    #[test]
3899    fn test_ipv4_addr() {
3900        proptest!(proptest_cfg(), |(addr: Ipv4Addr)| {
3901            let bincode_serialized = bincode::serialize(&addr).unwrap();
3902            let schema_serialized = serialize(&addr).unwrap();
3903            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3904
3905            let bincode_deserialized: Ipv4Addr = bincode::deserialize(&bincode_serialized).unwrap();
3906            let schema_deserialized: Ipv4Addr = deserialize(&schema_serialized).unwrap();
3907            prop_assert_eq!(addr, bincode_deserialized);
3908            prop_assert_eq!(addr, schema_deserialized);
3909        });
3910    }
3911
3912    #[test]
3913    fn test_ipv6_addr() {
3914        proptest!(proptest_cfg(), |(addr: Ipv6Addr)| {
3915            let bincode_serialized = bincode::serialize(&addr).unwrap();
3916            let schema_serialized = serialize(&addr).unwrap();
3917            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3918
3919            let bincode_deserialized: Ipv6Addr = bincode::deserialize(&bincode_serialized).unwrap();
3920            let schema_deserialized: Ipv6Addr = deserialize(&schema_serialized).unwrap();
3921            prop_assert_eq!(addr, bincode_deserialized);
3922            prop_assert_eq!(addr, schema_deserialized);
3923        });
3924    }
3925
3926    #[test]
3927    fn test_ip_addr() {
3928        proptest!(proptest_cfg(), |(addr: IpAddr)| {
3929            let bincode_serialized = bincode::serialize(&addr).unwrap();
3930            let schema_serialized = serialize(&addr).unwrap();
3931            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3932
3933            let bincode_deserialized: IpAddr = bincode::deserialize(&bincode_serialized).unwrap();
3934            let schema_deserialized: IpAddr = deserialize(&schema_serialized).unwrap();
3935            prop_assert_eq!(addr, bincode_deserialized);
3936            prop_assert_eq!(addr, schema_deserialized);
3937        });
3938    }
3939
3940    #[test]
3941    fn test_socket_addr_v4() {
3942        proptest!(proptest_cfg(), |(addr: SocketAddrV4)| {
3943            let bincode_serialized = bincode::serialize(&addr).unwrap();
3944            let schema_serialized = serialize(&addr).unwrap();
3945            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3946
3947            let bincode_deserialized: SocketAddrV4 = bincode::deserialize(&bincode_serialized).unwrap();
3948            let schema_deserialized: SocketAddrV4 = deserialize(&schema_serialized).unwrap();
3949            prop_assert_eq!(addr, bincode_deserialized);
3950            prop_assert_eq!(addr, schema_deserialized);
3951        });
3952    }
3953
3954    #[test]
3955    fn test_socket_addr_v6() {
3956        // serde drops flowinfo and scope_id for SocketAddrV6, so we only verify
3957        // byte compatibility and that both impls deserialize identically.
3958        proptest!(proptest_cfg(), |(addr: SocketAddrV6)| {
3959            let bincode_serialized = bincode::serialize(&addr).unwrap();
3960            let schema_serialized = serialize(&addr).unwrap();
3961            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3962
3963            let bincode_deserialized: SocketAddrV6 = bincode::deserialize(&bincode_serialized).unwrap();
3964            let schema_deserialized: SocketAddrV6 = deserialize(&schema_serialized).unwrap();
3965            prop_assert_eq!(bincode_deserialized, schema_deserialized);
3966        });
3967    }
3968
3969    #[test]
3970    fn test_socket_addr() {
3971        // serde drops flowinfo and scope_id for SocketAddrV6 variants, so we only
3972        // verify byte compatibility and that both impls deserialize identically.
3973        proptest!(proptest_cfg(), |(addr: SocketAddr)| {
3974            let bincode_serialized = bincode::serialize(&addr).unwrap();
3975            let schema_serialized = serialize(&addr).unwrap();
3976            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3977
3978            let bincode_deserialized: SocketAddr = bincode::deserialize(&bincode_serialized).unwrap();
3979            let schema_deserialized: SocketAddr = deserialize(&schema_serialized).unwrap();
3980            prop_assert_eq!(bincode_deserialized, schema_deserialized);
3981        });
3982    }
3983
3984    #[test]
3985    #[cfg(feature = "std")]
3986    fn test_system_time() {
3987        use std::time::{Duration, SystemTime, UNIX_EPOCH};
3988
3989        const MAX_SECS: u64 = i64::MAX as u64 - 1;
3990
3991        proptest!(proptest_cfg(), |(secs in 0u64..=MAX_SECS, nanos in 0u32..1_000_000_000u32)| {
3992            let time = UNIX_EPOCH + Duration::new(secs, nanos);
3993            let bincode_serialized = bincode::serialize(&time).unwrap();
3994            let schema_serialized = serialize(&time).unwrap();
3995            prop_assert_eq!(&bincode_serialized, &schema_serialized);
3996
3997            let bincode_deserialized: SystemTime = bincode::deserialize(&bincode_serialized).unwrap();
3998            let schema_deserialized: SystemTime = deserialize(&schema_serialized).unwrap();
3999            prop_assert_eq!(time, bincode_deserialized);
4000            prop_assert_eq!(time, schema_deserialized);
4001        });
4002    }
4003
4004    #[test]
4005    #[cfg(feature = "std")]
4006    fn test_system_time_before_epoch_errors() {
4007        use std::time::{Duration, UNIX_EPOCH};
4008
4009        let before_epoch = UNIX_EPOCH.checked_sub(Duration::from_secs(1)).unwrap();
4010        assert!(serialize(&before_epoch).is_err());
4011        // `serialized_size` must agree with `serialize`: a value that cannot be
4012        // written must not report a size.
4013        assert!(crate::serialized_size(&before_epoch).is_err());
4014    }
4015
4016    #[test]
4017    fn test_static_tuple_write_error_leaves_only_initialized_prefix() {
4018        let before_epoch = UNIX_EPOCH.checked_sub(Duration::from_secs(1)).unwrap();
4019        let value = (0xAAu8, before_epoch);
4020        let mut bytes = Vec::new();
4021
4022        assert!(crate::serialize_into(&mut bytes, &value).is_err());
4023        #[cfg(miri)]
4024        if bytes.len() > 1 {
4025            let _ = core::hint::black_box(bytes[1]);
4026        }
4027        assert_eq!(bytes, [0xAA]);
4028    }
4029
4030    #[test]
4031    fn test_deserialize_exact_accepts_exact_input() {
4032        let bytes = serialize(&123u64).unwrap();
4033        let value: u64 = deserialize_exact(&bytes).unwrap();
4034        assert_eq!(value, 123);
4035    }
4036
4037    #[test]
4038    fn test_deserialize_exact_rejects_trailing_bytes() {
4039        let mut bytes = serialize(&123u64).unwrap();
4040        bytes.push(0xAA);
4041        let err = deserialize_exact::<u64>(&bytes).unwrap_err();
4042        assert!(matches!(err, error::ReadError::TrailingBytes));
4043    }
4044
4045    #[test]
4046    fn test_config_deserialize_exact_rejects_trailing_bytes() {
4047        let config = Configuration::default();
4048        let mut bytes = config::serialize(&123u64, config).unwrap();
4049        bytes.push(0xAA);
4050        let err = config::deserialize_exact::<u64, _>(&bytes, config).unwrap_err();
4051        assert!(matches!(err, error::ReadError::TrailingBytes));
4052    }
4053
4054    #[test]
4055    #[cfg(feature = "std")]
4056    fn test_system_time_overflow_errors() {
4057        use {crate::serialize_into, std::time::SystemTime};
4058
4059        let mut bytes = Vec::with_capacity(size_of::<u64>() + size_of::<u32>());
4060        serialize_into(&mut bytes, &u64::MAX).unwrap();
4061        serialize_into(&mut bytes, &0u32).unwrap();
4062
4063        let result: ReadResult<SystemTime> = deserialize(&bytes);
4064        assert!(result.is_err());
4065    }
4066
4067    #[test]
4068    fn test_nonzero_types() {
4069        proptest!(proptest_cfg(), |(
4070            nz_u8: NonZeroU8,
4071            nz_u16: NonZeroU16,
4072            nz_u32: NonZeroU32,
4073            nz_u64: NonZeroU64,
4074            nz_u128: NonZeroU128,
4075            nz_usize: NonZeroUsize,
4076            nz_i8: NonZeroI8,
4077            nz_i16: NonZeroI16,
4078            nz_i32: NonZeroI32,
4079            nz_i64: NonZeroI64,
4080            nz_i128: NonZeroI128,
4081            nz_isize: NonZeroIsize,
4082        )| {
4083            // Unsigned
4084            let ser = serialize(&nz_u8).unwrap();
4085            let de: NonZeroU8 = deserialize(&ser).unwrap();
4086            prop_assert_eq!(nz_u8, de);
4087
4088            let ser = serialize(&nz_u16).unwrap();
4089            let de: NonZeroU16 = deserialize(&ser).unwrap();
4090            prop_assert_eq!(nz_u16, de);
4091
4092            let ser = serialize(&nz_u32).unwrap();
4093            let de: NonZeroU32 = deserialize(&ser).unwrap();
4094            prop_assert_eq!(nz_u32, de);
4095
4096            let ser = serialize(&nz_u64).unwrap();
4097            let de: NonZeroU64 = deserialize(&ser).unwrap();
4098            prop_assert_eq!(nz_u64, de);
4099
4100            let ser = serialize(&nz_u128).unwrap();
4101            let de: NonZeroU128 = deserialize(&ser).unwrap();
4102            prop_assert_eq!(nz_u128, de);
4103
4104            let ser = serialize(&nz_usize).unwrap();
4105            let de: NonZeroUsize = deserialize(&ser).unwrap();
4106            prop_assert_eq!(nz_usize, de);
4107
4108            // Signed
4109            let ser = serialize(&nz_i8).unwrap();
4110            let de: NonZeroI8 = deserialize(&ser).unwrap();
4111            prop_assert_eq!(nz_i8, de);
4112
4113            let ser = serialize(&nz_i16).unwrap();
4114            let de: NonZeroI16 = deserialize(&ser).unwrap();
4115            prop_assert_eq!(nz_i16, de);
4116
4117            let ser = serialize(&nz_i32).unwrap();
4118            let de: NonZeroI32 = deserialize(&ser).unwrap();
4119            prop_assert_eq!(nz_i32, de);
4120
4121            let ser = serialize(&nz_i64).unwrap();
4122            let de: NonZeroI64 = deserialize(&ser).unwrap();
4123            prop_assert_eq!(nz_i64, de);
4124
4125            let ser = serialize(&nz_i128).unwrap();
4126            let de: NonZeroI128 = deserialize(&ser).unwrap();
4127            prop_assert_eq!(nz_i128, de);
4128
4129            let ser = serialize(&nz_isize).unwrap();
4130            let de: NonZeroIsize = deserialize(&ser).unwrap();
4131            prop_assert_eq!(nz_isize, de);
4132        });
4133    }
4134
4135    #[test]
4136    fn test_nonzero_invalid_zero_value() {
4137        // Test that deserializing a zero value fails
4138        let zero_bytes = serialize(&0u32).unwrap();
4139        let result: ReadResult<NonZeroU32> = deserialize(&zero_bytes);
4140        assert!(
4141            result.is_err(),
4142            "Deserializing zero should fail for NonZeroU32"
4143        );
4144
4145        let zero_bytes = serialize(&0u64).unwrap();
4146        let result: ReadResult<NonZeroU64> = deserialize(&zero_bytes);
4147        assert!(
4148            result.is_err(),
4149            "Deserializing zero should fail for NonZeroU64"
4150        );
4151    }
4152
4153    #[test]
4154    fn test_bound_included_u64() {
4155        proptest!(proptest_cfg(), |(value in any::<u64>())| {
4156            let bound = Bound::Included(value);
4157            let serialized = serialize(&bound).unwrap();
4158            let deserialized: Bound<u64> = deserialize(&serialized).unwrap();
4159            prop_assert_eq!(&bound, &deserialized);
4160        });
4161    }
4162
4163    #[test]
4164    fn test_bound_excluded_u64() {
4165        proptest!(proptest_cfg(), |(value in any::<u64>())| {
4166            let bound = Bound::Excluded(value);
4167            let serialized = serialize(&bound).unwrap();
4168            let deserialized: Bound<u64> = deserialize(&serialized).unwrap();
4169            prop_assert_eq!(&bound, &deserialized);
4170        });
4171    }
4172
4173    #[test]
4174    fn test_bound_included_string() {
4175        proptest!(proptest_cfg(), |(value in any::<String>())| {
4176            let bound = Bound::Included(value);
4177            let serialized = serialize(&bound).unwrap();
4178            let deserialized: Bound<String> = deserialize(&serialized).unwrap();
4179            prop_assert_eq!(&bound, &deserialized);
4180        });
4181    }
4182
4183    #[test]
4184    fn test_bound_excluded_string() {
4185        proptest!(proptest_cfg(), |(value in any::<String>())| {
4186            let bound = Bound::Excluded(value);
4187            let serialized = serialize(&bound).unwrap();
4188            let deserialized: Bound<String> = deserialize(&serialized).unwrap();
4189            prop_assert_eq!(&bound, &deserialized);
4190        });
4191    }
4192
4193    #[test]
4194    fn test_bound_included_bincode_equivalence() {
4195        proptest!(proptest_cfg(), |(value in any::<u64>())| {
4196            let bound = Bound::Included(value);
4197            let wincode_serialized = serialize(&bound).unwrap();
4198            let bincode_serialized = bincode::serialize(&bound).unwrap();
4199            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
4200
4201            let wincode_deserialized: Bound<u64> = deserialize(&wincode_serialized).unwrap();
4202            let bincode_deserialized: Bound<u64> = bincode::deserialize(&bincode_serialized).unwrap();
4203            prop_assert_eq!(&bound, &wincode_deserialized);
4204            prop_assert_eq!(&wincode_deserialized, &bincode_deserialized);
4205        });
4206    }
4207
4208    #[test]
4209    fn test_bound_excluded_bincode_equivalence() {
4210        proptest!(proptest_cfg(), |(value in any::<u64>())| {
4211            let bound = Bound::Excluded(value);
4212            let wincode_serialized = serialize(&bound).unwrap();
4213            let bincode_serialized = bincode::serialize(&bound).unwrap();
4214            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
4215
4216            let wincode_deserialized: Bound<u64> = deserialize(&wincode_serialized).unwrap();
4217            let bincode_deserialized: Bound<u64> = bincode::deserialize(&bincode_serialized).unwrap();
4218            prop_assert_eq!(&bound, &wincode_deserialized);
4219            prop_assert_eq!(&wincode_deserialized, &bincode_deserialized);
4220        });
4221    }
4222
4223    #[test]
4224    fn test_range_u64() {
4225        proptest!(proptest_cfg(), |(start in any::<u64>(), end in any::<u64>())| {
4226            let range = Range { start, end };
4227            let serialized = serialize(&range).unwrap();
4228            let deserialized: Range<u64> = deserialize(&serialized).unwrap();
4229            prop_assert_eq!(range.start, deserialized.start);
4230            prop_assert_eq!(range.end, deserialized.end);
4231        });
4232    }
4233
4234    #[test]
4235    fn test_range_string() {
4236        proptest!(proptest_cfg(), |(start in any::<String>(), end in any::<String>())| {
4237            let range = Range { start, end };
4238            let serialized = serialize(&range).unwrap();
4239            let deserialized: Range<String> = deserialize(&serialized).unwrap();
4240            prop_assert_eq!(&range.start, &deserialized.start);
4241            prop_assert_eq!(&range.end, &deserialized.end);
4242        });
4243    }
4244
4245    #[test]
4246    fn test_range_bincode_equivalence() {
4247        proptest!(proptest_cfg(), |(start in any::<u64>(), end in any::<u64>())| {
4248            let range = Range { start, end };
4249            let wincode_serialized = serialize(&range).unwrap();
4250            let bincode_serialized = bincode::serialize(&range).unwrap();
4251            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
4252
4253            let wincode_deserialized: Range<u64> = deserialize(&wincode_serialized).unwrap(); //happens here
4254            let bincode_deserialized: Range<u64> = bincode::deserialize(&bincode_serialized).unwrap();
4255            prop_assert_eq!(range.start, wincode_deserialized.start);
4256            prop_assert_eq!(range.end, wincode_deserialized.end);
4257            prop_assert_eq!(wincode_deserialized.start, bincode_deserialized.start);
4258            prop_assert_eq!(wincode_deserialized.end, bincode_deserialized.end);
4259        });
4260    }
4261
4262    #[test]
4263    fn test_range_inclusive_u64() {
4264        proptest!(proptest_cfg(), |(start in any::<u64>(), end in any::<u64>())| {
4265            let range = RangeInclusive::new(start, end);
4266            let serialized = serialize(&range).unwrap();
4267            let deserialized: RangeInclusive<u64> = deserialize(&serialized).unwrap();
4268            prop_assert_eq!(range.start(), deserialized.start());
4269            prop_assert_eq!(range.end(), deserialized.end());
4270        });
4271    }
4272
4273    #[test]
4274    fn test_range_inclusive_string() {
4275        proptest!(proptest_cfg(), |(start in any::<String>(), end in any::<String>())| {
4276            let range = RangeInclusive::new(start, end );
4277            let serialized = serialize(&range).unwrap();
4278            let deserialized: RangeInclusive<String> = deserialize(&serialized).unwrap();
4279            prop_assert_eq!(&range.start(), &deserialized.start());
4280            prop_assert_eq!(&range.end(), &deserialized.end());
4281        });
4282    }
4283
4284    #[test]
4285    fn test_range_inclusive_bincode_equivalence() {
4286        proptest!(proptest_cfg(), |(start in any::<u64>(), end in any::<u64>())| {
4287            let range = RangeInclusive::new(start, end );
4288            let wincode_serialized = serialize(&range).unwrap();
4289            let bincode_serialized = bincode::serialize(&range).unwrap();
4290            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
4291
4292            let wincode_deserialized: RangeInclusive<u64> = deserialize(&wincode_serialized).unwrap();
4293            let bincode_deserialized: RangeInclusive<u64> = bincode::deserialize(&bincode_serialized).unwrap();
4294            prop_assert_eq!(range.start(), wincode_deserialized.start());
4295            prop_assert_eq!(range.end(), wincode_deserialized.end());
4296            prop_assert_eq!(wincode_deserialized.start(), bincode_deserialized.start());
4297            prop_assert_eq!(wincode_deserialized.end(), bincode_deserialized.end());
4298        });
4299    }
4300
4301    #[test]
4302    fn test_range_vec_u64() {
4303        proptest!(proptest_cfg(), |(ranges: Vec<Range<u64>>)| {
4304            let serialized = serialize(&ranges).unwrap();
4305            let bincode_serialized = bincode::serialize(&ranges).unwrap();
4306            prop_assert_eq!(&serialized, &bincode_serialized);
4307
4308            let deserialized: Vec<Range<u64>> = deserialize(&serialized).unwrap();
4309            let bincode_deserialized: Vec<Range<u64>> = bincode::deserialize(&bincode_serialized).unwrap();
4310            prop_assert_eq!(deserialized, bincode_deserialized);
4311        });
4312    }
4313
4314    #[test]
4315    fn test_range_inclusive_vec_u64() {
4316        proptest!(proptest_cfg(), |(ranges: Vec<RangeInclusive<u64>>)| {
4317            let serialized = serialize(&ranges).unwrap();
4318            let bincode_serialized = bincode::serialize(&ranges).unwrap();
4319            prop_assert_eq!(&serialized, &bincode_serialized);
4320
4321            let deserialized: Vec<RangeInclusive<u64>> = deserialize(&serialized).unwrap();
4322            let bincode_deserialized: Vec<RangeInclusive<u64>> = bincode::deserialize(&bincode_serialized).unwrap();
4323            prop_assert_eq!(deserialized, bincode_deserialized);
4324        });
4325    }
4326
4327    #[test]
4328    fn test_bound_vec_u64() {
4329        proptest!(proptest_cfg(), |(bounds: Vec<Bound<u64>>)| {
4330            let serialized = serialize(&bounds).unwrap();
4331            let bincode_serialized = bincode::serialize(&bounds).unwrap();
4332            prop_assert_eq!(&serialized, &bincode_serialized);
4333
4334            let deserialized: Vec<Bound<u64>> = deserialize(&serialized).unwrap();
4335            let bincode_deserialized: Vec<Bound<u64>> = bincode::deserialize(&bincode_serialized).unwrap();
4336            prop_assert_eq!(deserialized, bincode_deserialized);
4337        });
4338    }
4339
4340    #[test]
4341    fn test_byte_order_configuration() {
4342        let c = Configuration::default().with_big_endian();
4343        let bincode_c = bincode::DefaultOptions::new()
4344            .with_big_endian()
4345            .with_fixint_encoding();
4346
4347        proptest!(proptest_cfg(), |(value: Vec<u64>)| {
4348            let bincode_serialized = bincode_c.serialize(&value).unwrap();
4349            let serialized = config::serialize(&value, c).unwrap();
4350            prop_assert_eq!(&bincode_serialized, &serialized);
4351
4352            let deserialized: Vec<u64> = config::deserialize(&serialized, c).unwrap();
4353            let len = value.len();
4354            prop_assert_eq!(len, u64::from_be_bytes(serialized[0..8].try_into().unwrap()) as usize);
4355
4356            if !value.is_empty() {
4357                for (i, chunk) in serialized[8..].chunks(8).enumerate() {
4358                    let val = u64::from_be_bytes(chunk.try_into().unwrap());
4359                    prop_assert_eq!(val, value[i]);
4360                }
4361            }
4362
4363            prop_assert_eq!(value, deserialized);
4364        });
4365    }
4366
4367    #[test]
4368    fn test_duration_nanos_normalization() {
4369        use core::time::Duration;
4370
4371        proptest!(proptest_cfg(), |(secs in 0u64..u64::MAX/2, nanos in 1_000_000_000u32..=u32::MAX)| {
4372            let mut bytes: Vec<u8> = Vec::with_capacity(size_of::<u64>() + size_of::<u32>());
4373            crate::serialize_into(&mut bytes, &secs).unwrap();
4374            crate::serialize_into(&mut bytes, &nanos).unwrap();
4375
4376            let result: Duration = deserialize(&bytes).unwrap();
4377            let expected = Duration::new(secs, nanos);
4378            prop_assert_eq!(result, expected);
4379        });
4380    }
4381
4382    #[test]
4383    fn test_custom_length_encoding_and_byte_order() {
4384        let c = Configuration::default()
4385            .with_length_encoding::<FixIntLen<u32>>()
4386            .with_big_endian();
4387
4388        proptest!(proptest_cfg(), |(value: Vec<u8>)| {
4389            let serialized = config::serialize(&value, c).unwrap();
4390            let deserialized: Vec<u8> = config::deserialize(&serialized, c).unwrap();
4391            let len = value.len();
4392            prop_assert_eq!(len, u32::from_be_bytes(serialized[0..4].try_into().unwrap()) as usize);
4393            prop_assert_eq!(value, deserialized);
4394        });
4395    }
4396
4397    #[test]
4398    fn test_custom_primitive_length_encoding() {
4399        let c = Configuration::default().with_length_encoding::<u32>();
4400
4401        proptest!(proptest_cfg(), |(value: Vec<u8>)| {
4402            let serialized = config::serialize(&value, c).unwrap();
4403            let deserialized: Vec<u8> = config::deserialize(&serialized, c).unwrap();
4404            let len = value.len();
4405            prop_assert_eq!(len, u32::from_le_bytes(serialized[0..4].try_into().unwrap()) as usize);
4406            prop_assert_eq!(value, deserialized);
4407        });
4408    }
4409
4410    #[test]
4411    fn test_duration_overflow() {
4412        use core::time::Duration;
4413
4414        let mut bytes = Vec::with_capacity(size_of::<u64>() + size_of::<u32>());
4415        crate::serialize_into(&mut bytes, &u64::MAX).unwrap();
4416        crate::serialize_into(&mut bytes, &1_000_000_000u32).unwrap();
4417
4418        let result: error::ReadResult<Duration> = deserialize(&bytes);
4419        assert!(result.is_err());
4420    }
4421
4422    #[test]
4423    fn test_all_integers_with_custom_byte_order() {
4424        let c = Configuration::default().with_big_endian();
4425        let bincode_c = bincode::DefaultOptions::new()
4426            .with_big_endian()
4427            .with_fixint_encoding();
4428
4429        proptest!(proptest_cfg(), |(value: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize))| {
4430            let bincode_serialized = bincode_c.serialize(&value).unwrap();
4431            let serialized = config::serialize(&value, c).unwrap();
4432            prop_assert_eq!(&bincode_serialized, &serialized);
4433            let deserialized: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize) = config::deserialize(&serialized, c).unwrap();
4434            prop_assert_eq!(value, deserialized);
4435        });
4436    }
4437
4438    #[test]
4439    fn test_all_integers_with_varint() {
4440        let c = Configuration::default().with_varint_encoding();
4441        let bincode_c = bincode::DefaultOptions::new().with_varint_encoding();
4442
4443        proptest!(proptest_cfg(), |(value: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize))| {
4444            let bincode_serialized = bincode_c.serialize(&value).unwrap();
4445            let serialized = config::serialize(&value, c).unwrap();
4446            prop_assert_eq!(&bincode_serialized, &serialized);
4447            prop_assert_eq!(bincode_c.serialized_size(&value).unwrap(), config::serialized_size(&value, c).unwrap());
4448
4449            let deserialized: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize) = config::deserialize(&serialized, c).unwrap();
4450            prop_assert_eq!(value, deserialized);
4451        });
4452    }
4453
4454    #[test]
4455    fn test_all_integers_with_varint_big_endian() {
4456        let c = Configuration::default()
4457            .with_varint_encoding()
4458            .with_big_endian();
4459        let bincode_c = bincode::DefaultOptions::new()
4460            .with_varint_encoding()
4461            .with_big_endian();
4462
4463        proptest!(proptest_cfg(), |(value: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize))| {
4464            let bincode_serialized = bincode_c.serialize(&value).unwrap();
4465            let serialized = config::serialize(&value, c).unwrap();
4466            prop_assert_eq!(&bincode_serialized, &serialized);
4467            prop_assert_eq!(bincode_c.serialized_size(&value).unwrap(), config::serialized_size(&value, c).unwrap());
4468
4469            let deserialized: (u16, u32, u64, u128, i16, i32, i64, i128, usize, isize) = config::deserialize(&serialized, c).unwrap();
4470            prop_assert_eq!(value, deserialized);
4471        });
4472    }
4473
4474    #[test]
4475    fn test_varint_boundaries() {
4476        let c = Configuration::default().with_varint_encoding();
4477        let bincode_c = bincode::DefaultOptions::new().with_varint_encoding();
4478
4479        fn assert_varint_roundtrip<T, C, O>(val: T, c: C, bincode_c: O)
4480        where
4481            C: Config + Copy,
4482            O: Options + Copy,
4483            T: serde::Serialize
4484                + for<'de> Deserialize<'de>
4485                + PartialEq
4486                + core::fmt::Debug
4487                + SchemaWrite<C, Src = T>
4488                + for<'de> SchemaRead<'de, C, Dst = T>,
4489        {
4490            let bincode_serialized = bincode_c.serialize(&val).unwrap();
4491            let serialized = config::serialize(&val, c).unwrap();
4492            assert_eq!(bincode_serialized, serialized);
4493            assert_eq!(
4494                bincode_c.serialized_size(&val).unwrap(),
4495                config::serialized_size(&val, c).unwrap()
4496            );
4497            let deserialized: T = config::deserialize(&serialized, c).unwrap();
4498            assert_eq!(val, deserialized);
4499        }
4500
4501        for val in [0u16, 1, 250, 251, 252, u16::MAX] {
4502            assert_varint_roundtrip(val, c, bincode_c);
4503        }
4504
4505        for val in [
4506            0u32,
4507            1,
4508            250,
4509            251,
4510            252,
4511            u16::MAX as u32,
4512            u16::MAX as u32 + 1,
4513            u32::MAX,
4514        ] {
4515            assert_varint_roundtrip(val, c, bincode_c);
4516        }
4517
4518        for val in [
4519            0u64,
4520            1,
4521            250,
4522            251,
4523            252,
4524            u16::MAX as u64,
4525            u16::MAX as u64 + 1,
4526            u32::MAX as u64,
4527            u32::MAX as u64 + 1,
4528            u64::MAX,
4529        ] {
4530            assert_varint_roundtrip(val, c, bincode_c);
4531        }
4532
4533        for val in [
4534            0u128,
4535            1,
4536            250,
4537            251,
4538            252,
4539            u16::MAX as u128,
4540            u16::MAX as u128 + 1,
4541            u32::MAX as u128,
4542            u32::MAX as u128 + 1,
4543            u64::MAX as u128,
4544            u64::MAX as u128 + 1,
4545            u128::MAX,
4546        ] {
4547            assert_varint_roundtrip(val, c, bincode_c);
4548        }
4549
4550        for val in [0i16, 1, -1, 2, -2, i16::MIN, i16::MAX] {
4551            assert_varint_roundtrip(val, c, bincode_c);
4552        }
4553
4554        for val in [0i32, 1, -1, 2, -2, i32::MIN, i32::MAX] {
4555            assert_varint_roundtrip(val, c, bincode_c);
4556        }
4557
4558        for val in [0i64, 1, -1, 2, -2, i64::MIN, i64::MAX] {
4559            assert_varint_roundtrip(val, c, bincode_c);
4560        }
4561
4562        for val in [0i128, 1, -1, 2, -2, i128::MIN, i128::MAX] {
4563            assert_varint_roundtrip(val, c, bincode_c);
4564        }
4565    }
4566
4567    #[test]
4568    fn test_floats_with_custom_byte_order() {
4569        let c = Configuration::default().with_big_endian();
4570        let bincode_c = bincode::DefaultOptions::new()
4571            .with_big_endian()
4572            .with_fixint_encoding();
4573
4574        proptest!(proptest_cfg(), |(value: (f32, f64))| {
4575            let bincode_serialized = bincode_c.serialize(&value).unwrap();
4576            let serialized = config::serialize(&value, c).unwrap();
4577            prop_assert_eq!(&bincode_serialized, &serialized);
4578            let deserialized: (f32, f64) = config::deserialize(&serialized, c).unwrap();
4579            prop_assert_eq!(value, deserialized);
4580        });
4581    }
4582
4583    #[test]
4584    fn test_generic_struct() {
4585        #[derive(
4586            SchemaWrite,
4587            SchemaRead,
4588            serde::Serialize,
4589            serde::Deserialize,
4590            Debug,
4591            PartialEq,
4592            Eq,
4593            proptest_derive::Arbitrary,
4594        )]
4595        #[wincode(internal)]
4596        struct GenT<T> {
4597            inner: T,
4598        }
4599
4600        assert_eq!(
4601            <GenT<u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
4602            TypeMeta::Static {
4603                size: 8,
4604                zero_copy: false
4605            }
4606        );
4607
4608        assert_eq!(
4609            <GenT<String> as SchemaWrite<DefaultConfig>>::TYPE_META,
4610            TypeMeta::Dynamic,
4611        );
4612
4613        proptest!(proptest_cfg(), |(value: GenT<u64>)| {
4614            let serialized = serialize(&value).unwrap();
4615            let bincode_serialized = bincode::serialize(&value).unwrap();
4616            prop_assert_eq!(&serialized, &bincode_serialized);
4617            let deserialized: GenT<u64> = deserialize(&serialized).unwrap();
4618            let bincode_deserialized: GenT<u64> = bincode::deserialize(&bincode_serialized).unwrap();
4619            prop_assert_eq!(&deserialized, &bincode_deserialized);
4620            prop_assert_eq!(value, deserialized);
4621        });
4622    }
4623
4624    #[test]
4625    fn test_generic_struct_two_params() {
4626        #[derive(
4627            SchemaWrite,
4628            SchemaRead,
4629            serde::Serialize,
4630            serde::Deserialize,
4631            Debug,
4632            PartialEq,
4633            Eq,
4634            proptest_derive::Arbitrary,
4635        )]
4636        #[wincode(internal)]
4637        struct GenT<T, U> {
4638            t: T,
4639            u: U,
4640        }
4641
4642        assert_eq!(
4643            <GenT<u64, u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
4644            TypeMeta::Static {
4645                size: 16,
4646                zero_copy: false
4647            }
4648        );
4649
4650        assert_eq!(
4651            <GenT<String, u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
4652            TypeMeta::Dynamic,
4653        );
4654
4655        proptest!(proptest_cfg(), |(value: GenT<u64, u64>)| {
4656            let serialized = serialize(&value).unwrap();
4657            let bincode_serialized = bincode::serialize(&value).unwrap();
4658            prop_assert_eq!(&serialized, &bincode_serialized);
4659            let deserialized: GenT<u64, u64> = deserialize(&serialized).unwrap();
4660            let bincode_deserialized: GenT<u64, u64> = bincode::deserialize(&bincode_serialized).unwrap();
4661            prop_assert_eq!(&deserialized, &bincode_deserialized);
4662            prop_assert_eq!(value, deserialized);
4663        });
4664    }
4665
4666    #[test]
4667    fn test_generic_struct_repr_transparent() {
4668        #[derive(
4669            SchemaWrite,
4670            SchemaRead,
4671            serde::Serialize,
4672            serde::Deserialize,
4673            Debug,
4674            PartialEq,
4675            Eq,
4676            proptest_derive::Arbitrary,
4677        )]
4678        #[wincode(internal)]
4679        #[repr(transparent)]
4680        struct GenT<T> {
4681            inner: T,
4682        }
4683
4684        assert_eq!(
4685            <GenT<u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
4686            TypeMeta::Static {
4687                size: 8,
4688                zero_copy: true
4689            }
4690        );
4691
4692        proptest!(proptest_cfg(), |(value: GenT<u64>)| {
4693            let serialized = serialize(&value).unwrap();
4694            let bincode_serialized = bincode::serialize(&value).unwrap();
4695            prop_assert_eq!(&serialized, &bincode_serialized);
4696            let deserialized: GenT<u64> = deserialize(&serialized).unwrap();
4697            let bincode_deserialized: GenT<u64> = bincode::deserialize(&bincode_serialized).unwrap();
4698            prop_assert_eq!(&deserialized, &bincode_deserialized);
4699            prop_assert_eq!(value, deserialized);
4700        });
4701    }
4702
4703    #[test]
4704    fn test_generic_struct_with_existing_bound() {
4705        #[derive(
4706            SchemaWrite,
4707            SchemaRead,
4708            serde::Serialize,
4709            serde::Deserialize,
4710            Debug,
4711            PartialEq,
4712            Eq,
4713            proptest_derive::Arbitrary,
4714        )]
4715        #[wincode(internal)]
4716        #[repr(transparent)]
4717        struct GenT<T: Copy> {
4718            inner: T,
4719        }
4720
4721        proptest!(proptest_cfg(), |(value: GenT<u64>)| {
4722            let serialized = serialize(&value).unwrap();
4723            let bincode_serialized = bincode::serialize(&value).unwrap();
4724            prop_assert_eq!(&serialized, &bincode_serialized);
4725            let deserialized: GenT<u64> = deserialize(&serialized).unwrap();
4726            let bincode_deserialized: GenT<u64> = bincode::deserialize(&bincode_serialized).unwrap();
4727            prop_assert_eq!(&deserialized, &bincode_deserialized);
4728            prop_assert_eq!(value, deserialized);
4729        });
4730    }
4731
4732    #[test]
4733    fn test_generic_enum() {
4734        #[derive(
4735            SchemaWrite,
4736            SchemaRead,
4737            serde::Serialize,
4738            serde::Deserialize,
4739            Debug,
4740            PartialEq,
4741            Eq,
4742            proptest_derive::Arbitrary,
4743        )]
4744        #[wincode(internal)]
4745        enum GenT<T> {
4746            A(T),
4747            B(u8),
4748        }
4749
4750        assert_eq!(
4751            <GenT<u8> as SchemaWrite<DefaultConfig>>::TYPE_META,
4752            TypeMeta::Static {
4753                size: size_of::<u32>() + 1,
4754                zero_copy: false
4755            }
4756        );
4757
4758        assert_eq!(
4759            <GenT<u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
4760            TypeMeta::Dynamic,
4761        );
4762
4763        proptest!(proptest_cfg(), |(value: GenT<u64>)| {
4764            let serialized = serialize(&value).unwrap();
4765            let bincode_serialized = bincode::serialize(&value).unwrap();
4766            prop_assert_eq!(&serialized, &bincode_serialized);
4767            let deserialized: GenT<u64> = deserialize(&serialized).unwrap();
4768            let bincode_deserialized: GenT<u64> = bincode::deserialize(&bincode_serialized).unwrap();
4769            prop_assert_eq!(&deserialized, &bincode_deserialized);
4770            prop_assert_eq!(value, deserialized);
4771        });
4772    }
4773
4774    #[test]
4775    fn test_recursive_type() {
4776        #[derive(
4777            SchemaWrite, SchemaRead, PartialEq, Debug, serde::Serialize, serde::Deserialize,
4778        )]
4779        #[wincode(internal)]
4780        pub enum Value {
4781            Usize(usize),
4782            List(Vec<Value>),
4783        }
4784
4785        let val = Value::List(vec![Value::Usize(0), Value::List(vec![Value::Usize(1)])]);
4786        let bincode_serialized = bincode::serialize(&val).unwrap();
4787        let serialized = serialize(&val).unwrap();
4788        assert_eq!(&bincode_serialized, &serialized);
4789
4790        let deserialized: Value = deserialize(&serialized).unwrap();
4791        let bincode_deserialized: Value = bincode::deserialize(&bincode_serialized).unwrap();
4792        assert_eq!(&val, &bincode_deserialized);
4793        assert_eq!(val, deserialized);
4794    }
4795
4796    #[test]
4797    fn test_cow_str() {
4798        proptest!(proptest_cfg(), |(value: Cow<str>)| {
4799            let serialized = serialize(&value).unwrap();
4800            let bincode_serialized = bincode::serialize(&value).unwrap();
4801            prop_assert_eq!(&serialized, &bincode_serialized);
4802            let deserialized: Cow<str> = deserialize(&serialized).unwrap();
4803            let bincode_deserialized: Cow<str> = bincode::deserialize(&bincode_serialized).unwrap();
4804            prop_assert_eq!(&deserialized, &bincode_deserialized);
4805            prop_assert_eq!(value, deserialized);
4806        });
4807    }
4808
4809    #[test]
4810    fn test_cow_bytes() {
4811        proptest!(proptest_cfg(), |(value: Cow<[u8]>)| {
4812            let serialized = serialize(&value).unwrap();
4813            let bincode_serialized = bincode::serialize(&value).unwrap();
4814            prop_assert_eq!(&serialized, &bincode_serialized);
4815            let deserialized: Cow<[u8]> = deserialize(&serialized).unwrap();
4816            let bincode_deserialized: Cow<[u8]> = bincode::deserialize(&bincode_serialized).unwrap();
4817            prop_assert_eq!(&deserialized, &bincode_deserialized);
4818            prop_assert_eq!(value, deserialized);
4819        });
4820    }
4821
4822    #[test]
4823    fn test_cow_bytes_owned() {
4824        proptest!(proptest_cfg(), |(value: Cow<[u8]>)| {
4825            let serialized = serialize(&value).unwrap();
4826            let bincode_serialized = bincode::serialize(&value).unwrap();
4827            prop_assert_eq!(&serialized, &bincode_serialized);
4828            let deserialized = <Cow<[u8]> as SchemaRead<DefaultConfig>>
4829                ::get(NoBorrowReader::new(&serialized)).unwrap();
4830            let bincode_deserialized: Cow<[u8]> = bincode::deserialize_from(bincode_serialized.as_slice()).unwrap();
4831            prop_assert_eq!(&deserialized, &bincode_deserialized);
4832            prop_assert_eq!(value, deserialized);
4833        });
4834    }
4835
4836    #[test]
4837    fn test_cow_str_owned() {
4838        proptest!(proptest_cfg(), |(value: Cow<str>)| {
4839            let serialized = serialize(&value).unwrap();
4840            let bincode_serialized = bincode::serialize(&value).unwrap();
4841            prop_assert_eq!(&serialized, &bincode_serialized);
4842            let deserialized = <Cow<str> as SchemaRead<DefaultConfig>>
4843                ::get(NoBorrowReader::new(&serialized)).unwrap();
4844            let bincode_deserialized: Cow<str> = bincode::deserialize_from(bincode_serialized.as_slice()).unwrap();
4845            prop_assert_eq!(&deserialized, &bincode_deserialized);
4846            prop_assert_eq!(value, deserialized);
4847        });
4848    }
4849
4850    #[test]
4851    fn test_cow_ctx() {
4852        #[derive(Debug, PartialEq)]
4853        struct MaybeBorrowed<'a> {
4854            len: u8,
4855            data: Cow<'a, [u8]>,
4856        }
4857
4858        unsafe impl<'a, C: ConfigCore> SchemaWrite<C> for MaybeBorrowed<'a> {
4859            type Src = Self;
4860
4861            fn size_of(src: &Self::Src) -> WriteResult<usize> {
4862                Ok(1 + src.data.len())
4863            }
4864
4865            fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
4866                writer.write(&[src.data.len() as u8])?;
4867                writer.write(&src.data)?;
4868                Ok(())
4869            }
4870        }
4871
4872        unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for MaybeBorrowed<'de> {
4873            type Dst = Self;
4874
4875            fn read(
4876                mut reader: impl Reader<'de>,
4877                dst: &mut MaybeUninit<Self::Dst>,
4878            ) -> ReadResult<()> {
4879                let len = reader.take_byte()?;
4880                let cow = <Cow<'de, [u8]> as SchemaReadContext<C, _>>::get_with_context(
4881                    context::Len(len as usize),
4882                    reader,
4883                )?;
4884                dst.write(MaybeBorrowed { len, data: cow });
4885                Ok(())
4886            }
4887        }
4888
4889        proptest!(proptest_cfg(), |(value in proptest::collection::vec(any::<u8>(), 0..=64))| {
4890            let value = MaybeBorrowed {
4891                len: value.len() as u8,
4892                data: Cow::Owned(value),
4893            };
4894
4895            let serialized = serialize(&value).unwrap();
4896
4897            let deserialized = <MaybeBorrowed as SchemaRead<DefaultConfig>>
4898                ::get(NoBorrowReader::new(&serialized)).unwrap();
4899            prop_assert!(matches!(deserialized.data, Cow::Owned(_)));
4900            prop_assert_eq!(&value, &deserialized);
4901
4902            let deserialized: MaybeBorrowed = deserialize(&serialized).unwrap();
4903            prop_assert!(matches!(deserialized.data, Cow::Borrowed(_)));
4904            prop_assert_eq!(value, deserialized);
4905        });
4906    }
4907
4908    #[test]
4909    fn test_external_wincode() {
4910        use crate as my_wincode;
4911        #[derive(SchemaRead, SchemaWrite, Debug, PartialEq)]
4912        #[wincode(crate = "my_wincode")]
4913        struct Foo {
4914            bar: u8,
4915        }
4916
4917        let data = Foo { bar: 42 };
4918        let serialized = serialize(&data).unwrap();
4919        let deserialized: Foo = deserialize(&serialized).unwrap();
4920        assert_eq!(data, deserialized);
4921    }
4922
4923    #[test]
4924    fn test_mutex_roundtrip() {
4925        let value = Mutex::new(0x0123_4567_89ab_cdef_u64);
4926        let serialized = serialize(&value).unwrap();
4927        let deserialized: Mutex<u64> = deserialize(&serialized).unwrap();
4928
4929        assert_eq!(*value.lock().unwrap(), *deserialized.lock().unwrap());
4930        assert_eq!(
4931            <Mutex<u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
4932            TypeMeta::Static {
4933                size: size_of::<u64>(),
4934                zero_copy: false
4935            }
4936        );
4937        assert_eq!(
4938            <Mutex<u64> as SchemaRead<'_, DefaultConfig>>::TYPE_META,
4939            TypeMeta::Static {
4940                size: size_of::<u64>(),
4941                zero_copy: false
4942            }
4943        );
4944    }
4945
4946    #[test]
4947    fn test_mutex_write_errors_when_poisoned() {
4948        let value = Mutex::new(123_u32);
4949
4950        let _ = std::panic::catch_unwind(|| {
4951            let _guard = value.lock().unwrap();
4952            panic!("poison mutex for serialization test");
4953        });
4954
4955        assert!(value.is_poisoned());
4956        assert!(<Mutex<u32> as SchemaWrite<DefaultConfig>>::size_of(&value).is_err());
4957
4958        let mut bytes = Vec::new();
4959        assert!(<Mutex<u32> as SchemaWrite<DefaultConfig>>::write(&mut bytes, &value).is_err());
4960        assert!(serialize(&value).is_err());
4961    }
4962
4963    #[test]
4964    fn test_mutex_unsized_slice_write() {
4965        let value = Mutex::new([1_u8, 2, 3, 4]);
4966        let value: &Mutex<[u8]> = &value;
4967
4968        let serialized = <Mutex<[u8]> as Serialize>::serialize(value).unwrap();
4969        let expected = serialize(&[1_u8, 2, 3, 4][..]).unwrap();
4970
4971        assert_eq!(serialized, expected);
4972    }
4973
4974    #[test]
4975    fn test_rwlock_roundtrip() {
4976        let value = RwLock::new(0x0123_4567_89ab_cdef_u64);
4977        let serialized = serialize(&value).unwrap();
4978        let deserialized: RwLock<u64> = deserialize(&serialized).unwrap();
4979
4980        assert_eq!(*value.read().unwrap(), *deserialized.read().unwrap());
4981        assert_eq!(
4982            <RwLock<u64> as SchemaWrite<DefaultConfig>>::TYPE_META,
4983            TypeMeta::Static {
4984                size: size_of::<u64>(),
4985                zero_copy: false
4986            }
4987        );
4988        assert_eq!(
4989            <RwLock<u64> as SchemaRead<'_, DefaultConfig>>::TYPE_META,
4990            TypeMeta::Static {
4991                size: size_of::<u64>(),
4992                zero_copy: false
4993            }
4994        );
4995    }
4996
4997    #[test]
4998    fn test_rwlock_write_errors_when_poisoned() {
4999        let value = RwLock::new(123_u32);
5000
5001        let _ = std::panic::catch_unwind(|| {
5002            let _guard = value.write().unwrap();
5003            panic!("poison rwlock for serialization test");
5004        });
5005
5006        assert!(value.is_poisoned());
5007        assert!(<RwLock<u32> as SchemaWrite<DefaultConfig>>::size_of(&value).is_err());
5008
5009        let mut bytes = Vec::new();
5010        assert!(<RwLock<u32> as SchemaWrite<DefaultConfig>>::write(&mut bytes, &value).is_err());
5011        assert!(serialize(&value).is_err());
5012    }
5013
5014    #[test]
5015    fn test_rwlock_unsized_slice_write() {
5016        let value = RwLock::new([1_u8, 2, 3, 4]);
5017        let value: &RwLock<[u8]> = &value;
5018
5019        let serialized = <RwLock<[u8]> as Serialize>::serialize(value).unwrap();
5020        let expected = serialize(&[1_u8, 2, 3, 4][..]).unwrap();
5021
5022        assert_eq!(serialized, expected);
5023    }
5024
5025    // test using a struct that receives a T but only stores a T::SomeType
5026    #[test]
5027    fn test_generic_associated_type_only() {
5028        trait HasAssoc {
5029            type Value: for<'de> SchemaRead<'de, DefaultConfig, Dst = Self::Value>
5030                + SchemaWrite<DefaultConfig, Src = Self::Value>
5031                + Clone
5032                + core::fmt::Debug
5033                + PartialEq;
5034        }
5035
5036        #[derive(Debug, PartialEq)]
5037        struct UsesU64;
5038        impl HasAssoc for UsesU64 {
5039            type Value = u64;
5040        }
5041
5042        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Clone)]
5043        #[wincode(internal)]
5044        struct Wrapper<T: HasAssoc> {
5045            inner: T::Value,
5046        }
5047
5048        let original = Wrapper::<UsesU64> { inner: 42u64 };
5049        let serialized = serialize(&original).unwrap();
5050        let deserialized: Wrapper<UsesU64> = deserialize(&serialized).unwrap();
5051        assert_eq!(original, deserialized);
5052    }
5053
5054    // test using a struct that receives a T and stores it
5055    #[test]
5056    fn test_generic_direct_type() {
5057        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Clone)]
5058        #[wincode(internal)]
5059        struct Wrapper<T> {
5060            inner: T,
5061        }
5062
5063        let original = Wrapper::<String> {
5064            inner: "hello".into(),
5065        };
5066        let serialized = serialize(&original).unwrap();
5067        let deserialized: Wrapper<String> = deserialize(&serialized).unwrap();
5068        assert_eq!(original, deserialized);
5069    }
5070
5071    // test using a struct that receives a T and stores it plus the T::SomeType
5072    #[test]
5073    fn test_generic_direct_and_associated_type() {
5074        trait HasAssoc {
5075            type Extra: for<'de> SchemaRead<'de, DefaultConfig, Dst = Self::Extra>
5076                + SchemaWrite<DefaultConfig, Src = Self::Extra>
5077                + Clone
5078                + core::fmt::Debug
5079                + PartialEq;
5080        }
5081
5082        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Clone)]
5083        #[wincode(internal)]
5084        struct Both<T: HasAssoc> {
5085            direct: T,
5086            assoc: T::Extra,
5087        }
5088
5089        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Clone)]
5090        #[wincode(internal)]
5091        struct MyData {
5092            value: u32,
5093        }
5094
5095        impl HasAssoc for MyData {
5096            type Extra = String;
5097        }
5098
5099        let original = Both::<MyData> {
5100            direct: MyData { value: 42 },
5101            assoc: "hello".into(),
5102        };
5103        let serialized = serialize(&original).unwrap();
5104        let deserialized: Both<MyData> = deserialize(&serialized).unwrap();
5105        assert_eq!(original, deserialized);
5106    }
5107
5108    #[test]
5109    fn test_generic_type_with_container_adapter() {
5110        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Clone)]
5111        #[wincode(internal)]
5112        struct Wrapper<T> {
5113            #[wincode(with = "containers::Vec<_, BincodeLen>")]
5114            inner: Vec<T>,
5115        }
5116
5117        let original = Wrapper::<u8> {
5118            inner: vec![1, 2, 3],
5119        };
5120        let serialized = serialize(&original).unwrap();
5121        let deserialized: Wrapper<u8> = deserialize(&serialized).unwrap();
5122        assert_eq!(original, deserialized);
5123    }
5124
5125    #[test]
5126    fn test_generic_type_with_container_adapter_assoc() {
5127        trait HasAssoc {
5128            type Value: for<'de> SchemaRead<'de, DefaultConfig, Dst = Self::Value>
5129                + SchemaWrite<DefaultConfig, Src = Self::Value>
5130                + Clone
5131                + core::fmt::Debug
5132                + PartialEq;
5133        }
5134
5135        #[derive(Debug, PartialEq)]
5136        struct UsesU64;
5137        impl HasAssoc for UsesU64 {
5138            type Value = u64;
5139        }
5140
5141        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Clone)]
5142        #[wincode(internal)]
5143        struct Wrapper<T: HasAssoc> {
5144            #[wincode(with = "containers::Vec<_, BincodeLen>")]
5145            inner: Vec<T::Value>,
5146        }
5147
5148        let original = Wrapper::<UsesU64> {
5149            inner: vec![42, 67],
5150        };
5151        let serialized = serialize(&original).unwrap();
5152        let deserialized: Wrapper<UsesU64> = deserialize(&serialized).unwrap();
5153        assert_eq!(original, deserialized);
5154    }
5155
5156    #[test]
5157    fn test_bool_write_is_zero_copy_and_roundtrips() {
5158        // Write is zero-copy: the in-memory `bool` byte matches its serialized form.
5159        assert!(matches!(
5160            <bool as SchemaWrite<DefaultConfig>>::TYPE_META,
5161            TypeMeta::Static {
5162                size: 1,
5163                zero_copy: true
5164            }
5165        ));
5166
5167        // Exercises the bulk `write_slice_t` zero-copy branch for a contiguous `&[bool]`.
5168        let v: Vec<bool> = vec![true, false, true, true, false, false, true];
5169        let bytes = serialize(&v).unwrap();
5170        assert_eq!(bytes.len() - 8, v.len()); // 8-byte length prefix + one byte per bool
5171        assert_eq!(deserialize::<Vec<bool>>(&bytes).unwrap(), v);
5172
5173        let a: [bool; 5] = [true, false, false, true, true];
5174        let bytes = serialize(&a).unwrap();
5175        assert_eq!(deserialize::<[bool; 5]>(&bytes).unwrap(), a);
5176    }
5177
5178    #[test]
5179    fn test_invalid_bool_byte_still_rejected_on_read() {
5180        // Read must stay non-zero-copy: arbitrary bytes are invalid `bool` bit patterns
5181        // and require validation.
5182        assert!(matches!(
5183            <bool as SchemaRead<'_, DefaultConfig>>::TYPE_META,
5184            TypeMeta::Static {
5185                size: 1,
5186                zero_copy: false
5187            }
5188        ));
5189
5190        // Zero-copy write does not weaken read validation.
5191        let mut bytes = serialize(&vec![true, false]).unwrap();
5192        *bytes.last_mut().unwrap() = 2; // corrupt the second bool
5193        assert!(deserialize::<Vec<bool>>(&bytes).is_err());
5194    }
5195}