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