Skip to main content

wincode/schema/
mod.rs

1//! Schema traits.
2//!
3//! # Example
4//!
5//! ```
6//! # #[cfg(all(feature = "solana-short-vec", feature = "alloc"))] {
7//! # use rand::prelude::*;
8//! # use wincode::{Serialize, Deserialize, len::{BincodeLen, ShortU16Len}, containers::{self, Pod}};
9//! # use wincode_derive::{SchemaWrite, SchemaRead};
10//! # use std::array;
11//!
12//! # #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
13//! #[repr(transparent)]
14//! #[derive(Clone, Copy)]
15//! struct Signature([u8; 32]);
16//! # #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
17//! #[repr(transparent)]
18//! #[derive(Clone, Copy)]
19//! struct Address([u8; 32]);
20//!
21//! # #[derive(SchemaWrite, SchemaRead, serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
22//! struct MyStruct {
23//!     #[wincode(with = "containers::Vec<Pod<_>, BincodeLen>")]
24//!     signature: Vec<Signature>,
25//!     #[serde(with = "solana_short_vec")]
26//!     #[wincode(with = "containers::Vec<Pod<_>, ShortU16Len>")]
27//!     address: Vec<Address>,
28//! }
29//!
30//! let my_struct = MyStruct {
31//!     signature: (0..10).map(|_| Signature(array::from_fn(|_| random()))).collect(),
32//!     address: (0..10).map(|_| Address(array::from_fn(|_| random()))).collect(),
33//! };
34//! let bincode_serialized = bincode::serialize(&my_struct).unwrap();
35//! let wincode_serialized = wincode::serialize(&my_struct).unwrap();
36//! assert_eq!(bincode_serialized, wincode_serialized);
37//!
38//! let bincode_deserialized: MyStruct = bincode::deserialize(&bincode_serialized).unwrap();
39//! let wincode_deserialized: MyStruct = wincode::deserialize(&wincode_serialized).unwrap();
40//! assert_eq!(bincode_deserialized, wincode_deserialized);
41//! # }
42//! ```
43use {
44    crate::{
45        error::{ReadResult, WriteResult},
46        io::*,
47        len::SeqLen,
48    },
49    core::mem::MaybeUninit,
50};
51
52pub mod containers;
53mod impls;
54
55/// Indicates what kind of assumptions can be made when encoding or decoding a type.
56///
57/// Readers and writers may use this to optimize their behavior.
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum TypeMeta {
60    /// The type has a statically known serialized size.
61    ///
62    /// Specifying this variant can have significant performance benefits, as it can allow
63    /// writers to prefetch larger chunks of memory such that subsequent read/write operations
64    /// in those chunks can be performed at once without intermediate bounds checks.
65    ///
66    /// Specifying this variant incorrectly will almost certainly result in a panic at runtime.
67    ///
68    /// Take care not to specify this on variable length types, like `Vec` or `String`, as their
69    /// serialized size will vary based on their length.
70    Static {
71        /// The static serialized size of the type.
72        size: usize,
73        /// Whether the type is eligible for zero-copy encoding/decoding.
74        ///
75        /// This indicates that the type has no invalid bit patterns, no layout requirements, no endianness
76        /// checks, etc. This is a very strong claim that should be used judiciously.
77        ///
78        /// Specifying this incorrectly may trigger UB.
79        zero_copy: bool,
80    },
81    /// The type has a dynamic size, and no optimizations can be made.
82    Dynamic,
83}
84
85impl TypeMeta {
86    #[inline(always)]
87    pub(crate) const fn size_assert_zero_copy(self) -> usize {
88        match self {
89            TypeMeta::Static {
90                size,
91                zero_copy: true,
92            } => size,
93            _ => panic!("Type is not zero-copy"),
94        }
95    }
96}
97
98/// Types that can be written (serialized) to a [`Writer`].
99pub trait SchemaWrite {
100    type Src: ?Sized;
101
102    const TYPE_META: TypeMeta = TypeMeta::Dynamic;
103
104    /// Get the serialized size of `Self::Src`.
105    fn size_of(src: &Self::Src) -> WriteResult<usize>;
106    /// Write `Self::Src` to `writer`.
107    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()>;
108}
109
110/// Types that can be read (deserialized) from a [`Reader`].
111pub trait SchemaRead<'de> {
112    type Dst;
113
114    const TYPE_META: TypeMeta = TypeMeta::Dynamic;
115
116    /// Read into `dst` from `reader`.
117    ///
118    /// # Safety
119    ///
120    /// - Implementation must properly initialize the `Self::Dst`.
121    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()>;
122
123    /// Read `Self::Dst` from `reader` into a new `Self::Dst`.
124    #[inline(always)]
125    fn get(reader: &mut impl Reader<'de>) -> ReadResult<Self::Dst> {
126        let mut value = MaybeUninit::uninit();
127        Self::read(reader, &mut value)?;
128        // SAFETY: `read` must properly initialize the `Self::Dst`.
129        Ok(unsafe { value.assume_init() })
130    }
131}
132
133/// Marker trait for types that can be deserialized via direct borrows from a [`Reader`].
134///
135/// <div class="warning">
136/// You should not manually implement this trait for your own type unless you absolutely
137/// know what you're doing. The derive macros will automatically implement this trait for your type
138/// if it is eligible for zero-copy deserialization.
139/// </div>
140///
141/// # Safety
142///
143/// - The type must not have any invalid bit patterns, no layout requirements, no endianness checks, etc.
144pub unsafe trait ZeroCopy: 'static {
145    /// Get a reference to a type from the given bytes.
146    ///
147    /// # Examples
148    ///
149    /// ```
150    /// # #[cfg(all(feature = "alloc", feature = "derive"))] {
151    /// # use wincode::{SchemaWrite, SchemaRead, ZeroCopy};
152    /// # #[derive(Debug, PartialEq, Eq)]
153    /// #[derive(SchemaWrite, SchemaRead)]
154    /// #[repr(C)]
155    /// struct Data {
156    ///     bytes: [u8; 7],
157    ///     the_answer: u8,
158    /// }
159    ///
160    /// let data = Data { bytes: *b"wincode", the_answer: 42 };
161    ///
162    /// let serialized = wincode::serialize(&data).unwrap();
163    /// let data_ref = Data::from_bytes(&serialized).unwrap();
164    ///
165    /// assert_eq!(data_ref, &data);
166    /// # }
167    /// ```
168    #[inline(always)]
169    fn from_bytes<'de>(mut bytes: &'de [u8]) -> ReadResult<&'de Self>
170    where
171        Self: SchemaRead<'de, Dst = Self> + Sized,
172    {
173        <&Self as SchemaRead<'de>>::get(&mut bytes)
174    }
175
176    /// Get a mutable reference to a type from the given bytes.
177    ///
178    /// # Examples
179    ///
180    /// ```
181    /// # #[cfg(all(feature = "alloc", feature = "derive"))] {
182    /// # use wincode::{SchemaWrite, SchemaRead, ZeroCopy};
183    /// # #[derive(Debug, PartialEq, Eq)]
184    /// #[derive(SchemaWrite, SchemaRead)]
185    /// #[repr(C)]
186    /// struct Data {
187    ///     bytes: [u8; 7],
188    ///     the_answer: u8,
189    /// }
190    ///
191    /// let data = Data { bytes: [0; 7], the_answer: 0 };
192    ///
193    /// let mut serialized = wincode::serialize(&data).unwrap();
194    /// let data_mut = Data::from_bytes_mut(&mut serialized).unwrap();
195    /// data_mut.bytes = *b"wincode";
196    /// data_mut.the_answer = 42;
197    ///
198    /// let deserialized: Data = wincode::deserialize(&serialized).unwrap();
199    /// assert_eq!(deserialized, Data { bytes: *b"wincode", the_answer: 42 });
200    /// # }
201    /// ```
202    #[inline(always)]
203    fn from_bytes_mut<'de>(mut bytes: &'de mut [u8]) -> ReadResult<&'de mut Self>
204    where
205        Self: SchemaRead<'de, Dst = Self> + Sized,
206    {
207        <&mut Self as SchemaRead<'de>>::get(&mut bytes)
208    }
209}
210
211/// A type that can be read (deserialized) from a [`Reader`] without borrowing from it.
212pub trait SchemaReadOwned: for<'de> SchemaRead<'de> {}
213impl<T> SchemaReadOwned for T where T: for<'de> SchemaRead<'de> {}
214
215#[inline(always)]
216#[allow(clippy::arithmetic_side_effects)]
217fn size_of_elem_iter<'a, T, Len>(
218    value: impl ExactSizeIterator<Item = &'a T::Src>,
219) -> WriteResult<usize>
220where
221    Len: SeqLen,
222    T: SchemaWrite + 'a,
223{
224    if let TypeMeta::Static { size, .. } = T::TYPE_META {
225        return Ok(Len::write_bytes_needed(value.len())? + size * value.len());
226    }
227    // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
228    Ok(Len::write_bytes_needed(value.len())?
229        + (value
230            .map(T::size_of)
231            .try_fold(0usize, |acc, x| x.map(|x| acc + x))?))
232}
233
234#[inline(always)]
235#[allow(clippy::arithmetic_side_effects)]
236/// Variant of [`size_of_elem_iter`] specialized for slices, which can opt into
237/// an optimized implementation for bytes (`u8`s).
238fn size_of_elem_slice<T, Len>(value: &[T::Src]) -> WriteResult<usize>
239where
240    Len: SeqLen,
241    T: SchemaWrite,
242    T::Src: Sized,
243{
244    size_of_elem_iter::<T, Len>(value.iter())
245}
246
247#[inline(always)]
248fn write_elem_iter<'a, T, Len>(
249    writer: &mut impl Writer,
250    src: impl ExactSizeIterator<Item = &'a T::Src>,
251) -> WriteResult<()>
252where
253    Len: SeqLen,
254    T: SchemaWrite + 'a,
255{
256    if let TypeMeta::Static { size, .. } = T::TYPE_META {
257        #[allow(clippy::arithmetic_side_effects)]
258        let needed = Len::write_bytes_needed(src.len())? + size * src.len();
259        // SAFETY: `needed` is the size of the encoded length plus the size of the items.
260        // `Len::write` and len writes of `T::Src` will write `needed` bytes,
261        // fully initializing the trusted window.
262        let mut writer = unsafe { writer.as_trusted_for(needed) }?;
263        Len::write(&mut writer, src.len())?;
264        for item in src {
265            T::write(&mut writer, item)?;
266        }
267        writer.finish()?;
268        return Ok(());
269    }
270
271    Len::write(writer, src.len())?;
272    for item in src {
273        T::write(writer, item)?;
274    }
275    Ok(())
276}
277
278#[inline(always)]
279#[allow(clippy::arithmetic_side_effects)]
280/// Variant of [`write_elem_iter`] specialized for slices, which can opt into
281/// an optimized implementation for bytes (`u8`s).
282fn write_elem_slice<T, Len>(writer: &mut impl Writer, src: &[T::Src]) -> WriteResult<()>
283where
284    Len: SeqLen,
285    T: SchemaWrite,
286    T::Src: Sized,
287{
288    if let TypeMeta::Static {
289        size,
290        zero_copy: true,
291    } = T::TYPE_META
292    {
293        let needed = Len::write_bytes_needed(src.len())? + src.len() * size;
294        // SAFETY: `needed` is the size of the encoded length plus the size of the slice (bytes).
295        // `Len::write` and `writer.write(src)` will write `needed` bytes,
296        // fully initializing the trusted window.
297        let writer = &mut unsafe { writer.as_trusted_for(needed) }?;
298        Len::write(writer, src.len())?;
299        // SAFETY: `T::Src` is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
300        unsafe { writer.write_slice_t(src)? };
301        writer.finish()?;
302        return Ok(());
303    }
304    write_elem_iter::<T, Len>(writer, src.iter())
305}
306
307#[cfg(all(test, feature = "std", feature = "derive"))]
308mod tests {
309    #![allow(clippy::arithmetic_side_effects, deprecated)]
310
311    use {
312        crate::{
313            containers::{self, Elem, Pod},
314            deserialize, deserialize_mut,
315            error::{self, invalid_tag_encoding},
316            io::{Reader, Writer},
317            proptest_config::proptest_cfg,
318            serialize, Deserialize, ReadResult, SchemaRead, SchemaWrite, Serialize, TypeMeta,
319            WriteResult, ZeroCopy,
320        },
321        core::{marker::PhantomData, ptr},
322        proptest::prelude::*,
323        std::{
324            cell::Cell,
325            collections::{BinaryHeap, VecDeque},
326            mem::MaybeUninit,
327            ops::{Deref, DerefMut},
328            rc::Rc,
329            result::Result,
330            sync::Arc,
331        },
332    };
333
334    #[cfg(target_endian = "little")]
335    #[derive(
336        serde::Serialize,
337        serde::Deserialize,
338        Debug,
339        PartialEq,
340        Eq,
341        Ord,
342        PartialOrd,
343        SchemaWrite,
344        SchemaRead,
345        proptest_derive::Arbitrary,
346        Hash,
347        Clone,
348        Copy,
349    )]
350    #[wincode(internal)]
351    #[repr(C)]
352    struct StructZeroCopy {
353        a: u128,
354        b: i128,
355        c: u64,
356        d: i64,
357        e: u32,
358        f: i32,
359        ar1: [u8; 8],
360        g: u16,
361        h: i16,
362        ar2: [u8; 12],
363        i: u8,
364        j: i8,
365        ar3: [u8; 14],
366    }
367
368    #[cfg(not(target_endian = "little"))]
369    #[derive(
370        serde::Serialize,
371        serde::Deserialize,
372        Debug,
373        PartialEq,
374        Eq,
375        Ord,
376        PartialOrd,
377        SchemaWrite,
378        SchemaRead,
379        proptest_derive::Arbitrary,
380        Hash,
381        Clone,
382        Copy,
383    )]
384    #[wincode(internal)]
385    #[repr(C)]
386    struct StructZeroCopy {
387        byte: u8,
388        ar: [u8; 32],
389    }
390
391    #[derive(
392        serde::Serialize,
393        serde::Deserialize,
394        Debug,
395        PartialEq,
396        Eq,
397        Ord,
398        PartialOrd,
399        SchemaWrite,
400        SchemaRead,
401        proptest_derive::Arbitrary,
402        Hash,
403    )]
404    #[wincode(internal)]
405    struct StructStatic {
406        a: u64,
407        b: bool,
408        e: [u8; 32],
409    }
410
411    #[derive(
412        serde::Serialize,
413        serde::Deserialize,
414        Debug,
415        PartialEq,
416        Eq,
417        Ord,
418        PartialOrd,
419        SchemaWrite,
420        SchemaRead,
421        proptest_derive::Arbitrary,
422        Hash,
423    )]
424    #[wincode(internal)]
425    struct StructNonStatic {
426        a: u64,
427        b: bool,
428        e: String,
429    }
430
431    #[test]
432    fn struct_zero_copy_derive_size() {
433        #[cfg(target_endian = "little")]
434        let size = size_of::<u128>()
435            + size_of::<i128>()
436            + size_of::<u64>()
437            + size_of::<i64>()
438            + size_of::<u32>()
439            + size_of::<i32>()
440            + size_of::<[u8; 8]>()
441            + size_of::<u16>()
442            + size_of::<i16>()
443            + size_of::<[u8; 12]>()
444            + size_of::<u8>()
445            + size_of::<i8>()
446            + size_of::<[u8; 14]>();
447        #[cfg(not(target_endian = "little"))]
448        let size = size_of::<u8>() + size_of::<[u8; 32]>();
449        let expected = TypeMeta::Static {
450            size,
451            zero_copy: true,
452        };
453        assert_eq!(<StructZeroCopy as SchemaWrite>::TYPE_META, expected);
454        assert_eq!(<StructZeroCopy as SchemaRead<'_>>::TYPE_META, expected);
455    }
456
457    #[test]
458    fn struct_zero_copy_transparent_derive_size() {
459        #[derive(SchemaWrite, SchemaRead)]
460        #[wincode(internal)]
461        #[repr(transparent)]
462        struct Address([u8; 32]);
463
464        let expected = TypeMeta::Static {
465            size: size_of::<[u8; 32]>(),
466            zero_copy: true,
467        };
468        assert_eq!(<Address as SchemaWrite>::TYPE_META, expected);
469        assert_eq!(<Address as SchemaRead<'_>>::TYPE_META, expected);
470    }
471
472    #[test]
473    fn struct_static_derive_size() {
474        let expected = TypeMeta::Static {
475            size: size_of::<u64>() + size_of::<bool>() + size_of::<[u8; 32]>(),
476            zero_copy: false,
477        };
478        assert_eq!(<StructStatic as SchemaWrite>::TYPE_META, expected);
479        assert_eq!(<StructStatic as SchemaRead<'_>>::TYPE_META, expected);
480    }
481
482    #[test]
483    fn struct_non_static_derive_size() {
484        let expected = TypeMeta::Dynamic;
485        assert_eq!(<StructNonStatic as SchemaWrite>::TYPE_META, expected);
486        assert_eq!(<StructNonStatic as SchemaRead<'_>>::TYPE_META, expected);
487    }
488
489    thread_local! {
490        /// TL counter for tracking drops (or lack thereof -- a leak).
491        static TL_DROP_COUNT: Cell<isize> = const { Cell::new(0) };
492    }
493
494    fn get_tl_drop_count() -> isize {
495        TL_DROP_COUNT.with(|cell| cell.get())
496    }
497
498    fn tl_drop_count_inc() {
499        TL_DROP_COUNT.with(|cell| cell.set(cell.get() + 1));
500    }
501
502    fn tl_drop_count_dec() {
503        TL_DROP_COUNT.with(|cell| cell.set(cell.get() - 1));
504    }
505
506    fn tl_drop_count_reset() {
507        TL_DROP_COUNT.with(|cell| cell.set(0));
508    }
509
510    #[must_use]
511    #[derive(Debug)]
512    /// Guard for test set up that will ensure that the TL counter is 0 at the start and end of the test.
513    struct TLDropGuard;
514
515    impl TLDropGuard {
516        fn new() -> Self {
517            assert_eq!(
518                get_tl_drop_count(),
519                0,
520                "TL counter drifted from zero -- another test may have leaked"
521            );
522            Self
523        }
524    }
525
526    impl Drop for TLDropGuard {
527        #[track_caller]
528        fn drop(&mut self) {
529            let v = get_tl_drop_count();
530            if !std::thread::panicking() {
531                assert_eq!(
532                    v, 0,
533                    "TL counter drifted from zero -- this test might have leaked"
534                );
535            }
536            tl_drop_count_reset();
537        }
538    }
539
540    #[derive(Debug, PartialEq, Eq)]
541    /// A `SchemaWrite` and `SchemaRead` that will increment the TL counter when constructed.
542    struct DropCounted;
543
544    impl Arbitrary for DropCounted {
545        type Parameters = ();
546        type Strategy = Just<Self>;
547        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
548            Just(Self::new())
549        }
550    }
551
552    impl DropCounted {
553        const TAG_BYTE: u8 = 0;
554
555        fn new() -> Self {
556            tl_drop_count_inc();
557            Self
558        }
559    }
560
561    impl Clone for DropCounted {
562        fn clone(&self) -> Self {
563            tl_drop_count_inc();
564            Self
565        }
566    }
567
568    impl Drop for DropCounted {
569        fn drop(&mut self) {
570            tl_drop_count_dec();
571        }
572    }
573
574    impl SchemaWrite for DropCounted {
575        type Src = Self;
576
577        const TYPE_META: TypeMeta = TypeMeta::Static {
578            size: 1,
579            zero_copy: false,
580        };
581
582        fn size_of(_src: &Self::Src) -> WriteResult<usize> {
583            Ok(1)
584        }
585        fn write(writer: &mut impl Writer, _src: &Self::Src) -> WriteResult<()> {
586            u8::write(writer, &Self::TAG_BYTE)?;
587            Ok(())
588        }
589    }
590
591    impl<'de> SchemaRead<'de> for DropCounted {
592        type Dst = Self;
593
594        const TYPE_META: TypeMeta = TypeMeta::Static {
595            size: 1,
596            zero_copy: false,
597        };
598
599        fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
600            reader.consume(1)?;
601            // This will increment the counter.
602            dst.write(DropCounted::new());
603            Ok(())
604        }
605    }
606
607    /// A `SchemaRead` that will always error on read.
608    #[derive(Debug, Clone, Copy, PartialEq, Eq, proptest_derive::Arbitrary)]
609    struct ErrorsOnRead;
610
611    impl ErrorsOnRead {
612        const TAG_BYTE: u8 = 1;
613    }
614
615    impl SchemaWrite for ErrorsOnRead {
616        type Src = Self;
617
618        const TYPE_META: TypeMeta = TypeMeta::Static {
619            size: 1,
620            zero_copy: false,
621        };
622
623        fn size_of(_src: &Self::Src) -> WriteResult<usize> {
624            Ok(1)
625        }
626
627        fn write(writer: &mut impl Writer, _src: &Self::Src) -> WriteResult<()> {
628            u8::write(writer, &Self::TAG_BYTE)
629        }
630    }
631
632    impl<'de> SchemaRead<'de> for ErrorsOnRead {
633        type Dst = Self;
634
635        const TYPE_META: TypeMeta = TypeMeta::Static {
636            size: 1,
637            zero_copy: false,
638        };
639
640        fn read(
641            reader: &mut impl Reader<'de>,
642            _dst: &mut MaybeUninit<Self::Dst>,
643        ) -> ReadResult<()> {
644            reader.consume(1)?;
645            Err(error::ReadError::PointerSizedReadError)
646        }
647    }
648
649    #[derive(Debug, Clone, PartialEq, Eq, proptest_derive::Arbitrary)]
650    enum DropCountedMaybeError {
651        DropCounted(DropCounted),
652        ErrorsOnRead(ErrorsOnRead),
653    }
654
655    impl SchemaWrite for DropCountedMaybeError {
656        type Src = Self;
657
658        const TYPE_META: TypeMeta = TypeMeta::Static {
659            size: 1,
660            zero_copy: false,
661        };
662
663        fn size_of(src: &Self::Src) -> WriteResult<usize> {
664            match src {
665                DropCountedMaybeError::DropCounted(v) => DropCounted::size_of(v),
666                DropCountedMaybeError::ErrorsOnRead(v) => ErrorsOnRead::size_of(v),
667            }
668        }
669
670        fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
671            match src {
672                DropCountedMaybeError::DropCounted(v) => DropCounted::write(writer, v),
673                DropCountedMaybeError::ErrorsOnRead(v) => ErrorsOnRead::write(writer, v),
674            }
675        }
676    }
677
678    impl<'de> SchemaRead<'de> for DropCountedMaybeError {
679        type Dst = Self;
680
681        const TYPE_META: TypeMeta = TypeMeta::Static {
682            size: 1,
683            zero_copy: false,
684        };
685
686        fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
687            let byte = u8::get(reader)?;
688            match byte {
689                DropCounted::TAG_BYTE => {
690                    dst.write(DropCountedMaybeError::DropCounted(DropCounted::new()));
691                    Ok(())
692                }
693                ErrorsOnRead::TAG_BYTE => Err(error::ReadError::PointerSizedReadError),
694                _ => Err(invalid_tag_encoding(byte as usize)),
695            }
696        }
697    }
698
699    #[test]
700    fn drop_count_sanity() {
701        let _guard = TLDropGuard::new();
702        // Ensure our incrementing counter works
703        let serialized = { serialize(&[DropCounted::new(), DropCounted::new()]).unwrap() };
704        let _deserialized: [DropCounted; 2] = deserialize(&serialized).unwrap();
705        assert_eq!(get_tl_drop_count(), 2);
706    }
707
708    #[test]
709    fn drop_count_maybe_error_sanity() {
710        let _guard = TLDropGuard::new();
711        let serialized =
712            { serialize(&[DropCountedMaybeError::DropCounted(DropCounted::new())]).unwrap() };
713        let _deserialized: [DropCountedMaybeError; 1] = deserialize(&serialized).unwrap();
714        assert_eq!(get_tl_drop_count(), 1);
715
716        let serialized = {
717            serialize(&[
718                DropCountedMaybeError::DropCounted(DropCounted::new()),
719                DropCountedMaybeError::ErrorsOnRead(ErrorsOnRead),
720            ])
721            .unwrap()
722        };
723        let _deserialized: ReadResult<[DropCountedMaybeError; 2]> = deserialize(&serialized);
724    }
725
726    /// Test that the derive macro handles drops of initialized fields on partially initialized structs.
727    #[test]
728    fn test_struct_derive_handles_partial_drop() {
729        /// Represents a struct that would leak if the derive macro didn't handle drops of initialized fields
730        /// on error.
731        #[derive(SchemaWrite, SchemaRead, proptest_derive::Arbitrary, Debug, PartialEq, Eq)]
732        #[wincode(internal)]
733        struct CouldLeak {
734            data: DropCountedMaybeError,
735            data2: DropCountedMaybeError,
736            data3: DropCountedMaybeError,
737        }
738
739        let _guard = TLDropGuard::new();
740        proptest!(proptest_cfg(), |(could_leak: CouldLeak)| {
741            let serialized = serialize(&could_leak).unwrap();
742            let deserialized = CouldLeak::deserialize(&serialized);
743            if let Ok(deserialized) = deserialized {
744                prop_assert_eq!(could_leak, deserialized);
745            }
746        });
747    }
748
749    // Odd use case, but it's technically valid so we test it.
750    #[test]
751    fn test_vec_of_references_borrows_from_input() {
752        #[derive(
753            SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy,
754        )]
755        #[wincode(internal)]
756        #[repr(transparent)]
757        struct BigBytes([u8; 512]);
758        proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<BigBytes>(), 0..=8))| {
759            // Serialize as owned bytes.
760            let bytes = serialize(&vec).unwrap();
761            let borrowed: Vec<&BigBytes> = deserialize(&bytes).unwrap();
762
763            prop_assert_eq!(borrowed.len(), vec.len());
764            let start = bytes.as_ptr().addr();
765            let end = start + bytes.len();
766            for (i, r) in borrowed.iter().enumerate() {
767                // Values match
768                prop_assert_eq!(**r, vec[i]);
769                // References point into the input buffer
770                let p = ptr::from_ref(*r).addr();
771                prop_assert!(p >= start && p < end);
772            }
773        });
774    }
775
776    // Odd use case, but it's technically valid so we test it.
777    #[test]
778    fn test_boxed_slice_of_references_borrows_from_input() {
779        #[derive(
780            SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy,
781        )]
782        #[wincode(internal)]
783        #[repr(transparent)]
784        struct BigBytes([u8; 512]);
785        proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<BigBytes>(), 0..=8))| {
786            let boxed: Box<[BigBytes]> = vec.into_boxed_slice();
787            let bytes = serialize(&boxed).unwrap();
788            let borrowed: Box<[&BigBytes]> = deserialize(&bytes).unwrap();
789
790            prop_assert_eq!(borrowed.len(), boxed.len());
791            let start = bytes.as_ptr().addr();
792            let end = start + bytes.len();
793            for (i, &r) in borrowed.iter().enumerate() {
794                prop_assert_eq!(*r, boxed[i]);
795                let p = ptr::from_ref(r).addr();
796                prop_assert!(p >= start && p < end);
797            }
798        });
799    }
800
801    /// Test that the derive macro handles drops of initialized fields on partially initialized enums.
802    #[test]
803    fn test_enum_derive_handles_partial_drop() {
804        /// Represents an enum that would leak if the derive macro didn't handle drops of initialized fields
805        /// on error.
806        #[derive(SchemaWrite, SchemaRead, proptest_derive::Arbitrary, Debug, PartialEq, Eq)]
807        #[wincode(internal)]
808        enum CouldLeak {
809            A {
810                a: DropCountedMaybeError,
811                b: DropCountedMaybeError,
812            },
813            B(
814                DropCountedMaybeError,
815                DropCountedMaybeError,
816                DropCountedMaybeError,
817            ),
818            C(DropCountedMaybeError),
819            D,
820        }
821
822        let _guard = TLDropGuard::new();
823        proptest!(proptest_cfg(), |(could_leak: CouldLeak)| {
824            let serialized = serialize(&could_leak).unwrap();
825            let deserialized = CouldLeak::deserialize(&serialized);
826            if let Ok(deserialized) = deserialized {
827                prop_assert_eq!(could_leak, deserialized);
828            }
829        });
830    }
831
832    #[test]
833    fn test_tuple_handles_partial_drop() {
834        let _guard = TLDropGuard::new();
835        let serialized =
836            { serialize(&(DropCounted::new(), DropCounted::new(), ErrorsOnRead)).unwrap() };
837        let deserialized = <(DropCounted, DropCounted, ErrorsOnRead)>::deserialize(&serialized);
838        assert!(deserialized.is_err());
839    }
840
841    #[test]
842    fn test_vec_handles_partial_drop() {
843        let _guard = TLDropGuard::new();
844        proptest!(proptest_cfg(), |(vec in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100))| {
845            let serialized = serialize(&vec).unwrap();
846            let deserialized = <Vec<DropCountedMaybeError>>::deserialize(&serialized);
847            if let Ok(deserialized) = deserialized {
848                prop_assert_eq!(vec, deserialized);
849            }
850        });
851    }
852
853    #[test]
854    fn test_vec_deque_handles_partial_drop() {
855        let _guard = TLDropGuard::new();
856        proptest!(proptest_cfg(), |(vec in proptest::collection::vec_deque(any::<DropCountedMaybeError>(), 0..100))| {
857            let serialized = serialize(&vec).unwrap();
858            let deserialized = <VecDeque<DropCountedMaybeError>>::deserialize(&serialized);
859            if let Ok(deserialized) = deserialized {
860                prop_assert_eq!(vec, deserialized);
861            }
862        });
863    }
864
865    #[test]
866    fn test_boxed_slice_handles_partial_drop() {
867        let _guard = TLDropGuard::new();
868        proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100).prop_map(|vec| vec.into_boxed_slice()))| {
869            let serialized = serialize(&slice).unwrap();
870            let deserialized = <Box<[DropCountedMaybeError]>>::deserialize(&serialized);
871            if let Ok(deserialized) = deserialized {
872                prop_assert_eq!(slice, deserialized);
873            }
874        });
875    }
876
877    #[test]
878    fn test_rc_slice_handles_partial_drop() {
879        let _guard = TLDropGuard::new();
880        proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100).prop_map(Rc::from))| {
881            let serialized = serialize(&slice).unwrap();
882            let deserialized = <Rc<[DropCountedMaybeError]>>::deserialize(&serialized);
883            if let Ok(deserialized) = deserialized {
884                prop_assert_eq!(slice, deserialized);
885            }
886        });
887    }
888
889    #[test]
890    fn test_arc_slice_handles_partial_drop() {
891        let _guard = TLDropGuard::new();
892        proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<DropCountedMaybeError>(), 0..100).prop_map(Arc::from))| {
893            let serialized = serialize(&slice).unwrap();
894            let deserialized = <Arc<[DropCountedMaybeError]>>::deserialize(&serialized);
895            if let Ok(deserialized) = deserialized {
896                prop_assert_eq!(slice, deserialized);
897            }
898        });
899    }
900
901    #[test]
902    fn test_arc_handles_drop() {
903        let _guard = TLDropGuard::new();
904        proptest!(proptest_cfg(), |(data in any::<DropCountedMaybeError>().prop_map(Rc::from))| {
905            let serialized = serialize(&data).unwrap();
906            let deserialized = deserialize(&serialized);
907            if let Ok(deserialized) = deserialized {
908                prop_assert_eq!(data, deserialized);
909            }
910        });
911    }
912
913    #[test]
914    fn test_rc_handles_drop() {
915        let _guard = TLDropGuard::new();
916        proptest!(proptest_cfg(), |(data in any::<DropCountedMaybeError>().prop_map(Rc::from))| {
917            let serialized = serialize(&data).unwrap();
918            let deserialized = deserialize(&serialized);
919            if let Ok(deserialized) = deserialized {
920                prop_assert_eq!(data, deserialized);
921            }
922        });
923    }
924
925    #[test]
926    fn test_box_handles_drop() {
927        let _guard = TLDropGuard::new();
928        proptest!(proptest_cfg(), |(data in any::<DropCountedMaybeError>().prop_map(Box::new))| {
929            let serialized = serialize(&data).unwrap();
930            let deserialized = deserialize(&serialized);
931            if let Ok(deserialized) = deserialized {
932                prop_assert_eq!(data, deserialized);
933            }
934        });
935    }
936
937    #[test]
938    fn test_array_handles_partial_drop() {
939        let _guard = TLDropGuard::new();
940
941        proptest!(proptest_cfg(), |(array in proptest::array::uniform32(any::<DropCountedMaybeError>()))| {
942            let serialized = serialize(&array).unwrap();
943            let deserialized = <[DropCountedMaybeError; 32]>::deserialize(&serialized);
944            if let Ok(deserialized) = deserialized {
945                prop_assert_eq!(array, deserialized);
946            }
947        });
948    }
949
950    #[test]
951    fn test_struct_extensions_builder_handles_partial_drop() {
952        #[derive(SchemaWrite, SchemaRead, Debug, proptest_derive::Arbitrary)]
953        #[wincode(internal, struct_extensions)]
954        struct Test {
955            a: DropCounted,
956            b: DropCounted,
957            c: DropCounted,
958        }
959
960        {
961            let _guard = TLDropGuard::new();
962            proptest!(proptest_cfg(), |(test: Test)| {
963                let serialized = serialize(&test).unwrap();
964                let mut test = MaybeUninit::<Test>::uninit();
965                let reader = &mut serialized.as_slice();
966                let mut builder = TestUninitBuilder::from_maybe_uninit_mut(&mut test);
967                builder.read_a(reader)?.read_b(reader)?;
968                prop_assert!(!builder.is_init());
969                // Struct is not fully initialized, so the two initialized fields should be dropped.
970            });
971        }
972
973        #[derive(SchemaWrite, SchemaRead, Debug, proptest_derive::Arbitrary)]
974        #[wincode(internal, struct_extensions)]
975        // Same test, but with a tuple struct.
976        struct TestTuple(DropCounted, DropCounted);
977
978        {
979            let _guard = TLDropGuard::new();
980            proptest!(proptest_cfg(), |(test: TestTuple)| {
981                let serialized = serialize(&test).unwrap();
982                let mut test = MaybeUninit::<TestTuple>::uninit();
983                let reader = &mut serialized.as_slice();
984                let mut builder = TestTupleUninitBuilder::from_maybe_uninit_mut(&mut test);
985                builder.read_0(reader)?;
986                prop_assert!(!builder.is_init());
987                // Struct is not fully initialized, so the first initialized field should be dropped.
988            });
989        }
990    }
991
992    #[test]
993    fn test_struct_extensions_nested_builder_handles_partial_drop() {
994        #[derive(SchemaWrite, SchemaRead, Debug, proptest_derive::Arbitrary)]
995        #[wincode(internal, struct_extensions)]
996        struct Inner {
997            a: DropCounted,
998            b: DropCounted,
999            c: DropCounted,
1000        }
1001
1002        #[derive(SchemaWrite, SchemaRead, Debug, proptest_derive::Arbitrary)]
1003        #[wincode(internal, struct_extensions)]
1004        struct Test {
1005            inner: Inner,
1006            b: DropCounted,
1007        }
1008
1009        {
1010            let _guard = TLDropGuard::new();
1011            proptest!(proptest_cfg(), |(test: Test)| {
1012                let serialized = serialize(&test).unwrap();
1013                let mut test = MaybeUninit::<Test>::uninit();
1014                let reader = &mut serialized.as_slice();
1015                let mut outer_builder = TestUninitBuilder::from_maybe_uninit_mut(&mut test);
1016                unsafe {
1017                    outer_builder.init_inner_with(|inner| {
1018                        let mut inner_builder = InnerUninitBuilder::from_maybe_uninit_mut(inner);
1019                        inner_builder.read_a(reader)?;
1020                        inner_builder.read_b(reader)?;
1021                        inner_builder.read_c(reader)?;
1022                        assert!(inner_builder.is_init());
1023                        inner_builder.finish();
1024                        Ok(())
1025                    })?;
1026                }
1027                // Outer struct is not fully initialized, so the inner struct should be dropped.
1028            });
1029        }
1030    }
1031
1032    #[test]
1033    fn test_struct_extensions_nested_fully_initialized() {
1034        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1035        #[wincode(internal, struct_extensions)]
1036        struct Inner {
1037            a: DropCounted,
1038            b: DropCounted,
1039            c: DropCounted,
1040        }
1041
1042        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1043        #[wincode(internal, struct_extensions)]
1044        struct Test {
1045            inner: Inner,
1046            b: DropCounted,
1047        }
1048
1049        {
1050            let _guard = TLDropGuard::new();
1051            proptest!(proptest_cfg(), |(test: Test)| {
1052                let serialized = serialize(&test).unwrap();
1053                let mut uninit = MaybeUninit::<Test>::uninit();
1054                let reader = &mut serialized.as_slice();
1055                let mut outer_builder = TestUninitBuilder::from_maybe_uninit_mut(&mut uninit);
1056                unsafe {
1057                    outer_builder.init_inner_with(|inner| {
1058                        let mut inner_builder = InnerUninitBuilder::from_maybe_uninit_mut(inner);
1059                        inner_builder.read_a(reader)?;
1060                        inner_builder.read_b(reader)?;
1061                        inner_builder.read_c(reader)?;
1062                        assert!(inner_builder.is_init());
1063                        inner_builder.finish();
1064                        Ok(())
1065                    })?;
1066                }
1067                outer_builder.read_b(reader)?;
1068                prop_assert!(outer_builder.is_init());
1069                outer_builder.finish();
1070                let init = unsafe { uninit.assume_init() };
1071                prop_assert_eq!(test, init);
1072            });
1073        }
1074    }
1075
1076    #[test]
1077    fn test_struct_extensions() {
1078        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1079        #[wincode(internal, struct_extensions)]
1080        struct Test {
1081            a: Vec<u8>,
1082            b: [u8; 32],
1083            c: u64,
1084        }
1085
1086        proptest!(proptest_cfg(), |(test: Test)| {
1087            let serialized = serialize(&test).unwrap();
1088            let mut uninit = MaybeUninit::<Test>::uninit();
1089            let reader = &mut serialized.as_slice();
1090            let mut builder = TestUninitBuilder::from_maybe_uninit_mut(&mut uninit);
1091            builder
1092                .read_a(reader)?
1093                .read_b(reader)?
1094                .write_c(test.c);
1095            prop_assert!(builder.is_init());
1096            builder.finish();
1097            let init = unsafe { uninit.assume_init() };
1098            prop_assert_eq!(test, init);
1099        });
1100    }
1101
1102    #[test]
1103    fn test_struct_extensions_with_container() {
1104        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1105        #[wincode(internal, struct_extensions)]
1106        struct Test {
1107            #[wincode(with = "containers::Vec<Pod<_>>")]
1108            a: Vec<u8>,
1109            #[wincode(with = "containers::Pod<_>")]
1110            b: [u8; 32],
1111            c: u64,
1112        }
1113
1114        proptest!(proptest_cfg(), |(test: Test)| {
1115            let mut uninit = MaybeUninit::<Test>::uninit();
1116            let mut builder = TestUninitBuilder::from_maybe_uninit_mut(&mut uninit);
1117            builder
1118                .write_a(test.a.clone())
1119                .write_b(test.b)
1120                .write_c(test.c);
1121            prop_assert!(builder.is_init());
1122            let init_mut = unsafe { builder.into_assume_init_mut() };
1123            prop_assert_eq!(&test, init_mut);
1124            // Ensure `uninit` is marked initialized so fields are dropped.
1125            let init = unsafe { uninit.assume_init() };
1126            prop_assert_eq!(test, init);
1127        });
1128    }
1129
1130    #[test]
1131    fn test_struct_extensions_with_reference() {
1132        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1133        #[wincode(internal)]
1134        struct Test {
1135            a: Vec<u8>,
1136            b: Option<String>,
1137        }
1138
1139        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
1140        #[wincode(internal, struct_extensions)]
1141        struct TestRef<'a> {
1142            a: &'a [u8],
1143            b: Option<&'a str>,
1144        }
1145
1146        proptest!(proptest_cfg(), |(test: Test)| {
1147            let mut uninit = MaybeUninit::<TestRef>::uninit();
1148            let mut builder = TestRefUninitBuilder::from_maybe_uninit_mut(&mut uninit);
1149            builder
1150                .write_a(test.a.as_slice())
1151                .write_b(test.b.as_deref());
1152            prop_assert!(builder.is_init());
1153            builder.finish();
1154            let init = unsafe { uninit.assume_init() };
1155            prop_assert_eq!(test.a.as_slice(), init.a);
1156            prop_assert_eq!(test.b.as_deref(), init.b);
1157        });
1158    }
1159
1160    #[test]
1161    fn test_struct_extensions_with_mapped_type() {
1162        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1163        #[wincode(internal)]
1164        struct Test {
1165            a: Vec<u8>,
1166            b: [u8; 32],
1167            c: u64,
1168        }
1169
1170        #[derive(SchemaWrite, SchemaRead)]
1171        #[wincode(internal, from = "Test", struct_extensions)]
1172        struct TestMapped {
1173            a: containers::Vec<containers::Pod<u8>>,
1174            b: containers::Pod<[u8; 32]>,
1175            c: u64,
1176        }
1177
1178        proptest!(proptest_cfg(), |(test: Test)| {
1179            let mut uninit = MaybeUninit::<Test>::uninit();
1180            let mut builder = TestMappedUninitBuilder::from_maybe_uninit_mut(&mut uninit);
1181            builder
1182                .write_a(test.a.clone())
1183                .write_b(test.b)
1184                .write_c(test.c);
1185            prop_assert!(builder.is_init());
1186            builder.finish();
1187            let init = unsafe { uninit.assume_init() };
1188            prop_assert_eq!(test, init);
1189        });
1190    }
1191
1192    #[test]
1193    fn test_struct_extensions_builder_fully_initialized() {
1194        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1195        #[wincode(internal, struct_extensions)]
1196        struct Test {
1197            a: DropCounted,
1198            b: DropCounted,
1199            c: DropCounted,
1200        }
1201
1202        {
1203            let _guard = TLDropGuard::new();
1204            proptest!(proptest_cfg(), |(test: Test)| {
1205                let serialized = serialize(&test).unwrap();
1206                let mut uninit = MaybeUninit::<Test>::uninit();
1207                let reader = &mut serialized.as_slice();
1208                let mut builder = TestUninitBuilder::from_maybe_uninit_mut(&mut uninit);
1209                builder
1210                    .read_a(reader)?
1211                    .read_b(reader)?
1212                    .read_c(reader)?;
1213                prop_assert!(builder.is_init());
1214                let init = unsafe { builder.into_assume_init_mut() };
1215                prop_assert_eq!(&test, init);
1216
1217                let init = unsafe { uninit.assume_init() };
1218                prop_assert_eq!(test, init);
1219            });
1220        }
1221
1222        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
1223        #[wincode(internal, struct_extensions)]
1224        // Same test, but with a tuple struct.
1225        struct TestTuple(DropCounted, DropCounted);
1226
1227        {
1228            let _guard = TLDropGuard::new();
1229            proptest!(proptest_cfg(), |(test: TestTuple)| {
1230                let serialized = serialize(&test).unwrap();
1231                let mut uninit = MaybeUninit::<TestTuple>::uninit();
1232                let reader = &mut serialized.as_slice();
1233                let mut builder = TestTupleUninitBuilder::from_maybe_uninit_mut(&mut uninit);
1234                builder
1235                    .read_0(reader)?
1236                    .read_1(reader)?;
1237                assert!(builder.is_init());
1238                builder.finish();
1239
1240                let init = unsafe { uninit.assume_init() };
1241                prop_assert_eq!(test, init);
1242            });
1243        }
1244    }
1245
1246    #[test]
1247    fn test_struct_with_reference_equivalence() {
1248        #[derive(
1249            SchemaWrite, SchemaRead, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize,
1250        )]
1251        #[wincode(internal)]
1252        struct WithReference<'a> {
1253            data: &'a str,
1254            id: u64,
1255        }
1256
1257        proptest!(proptest_cfg(), |(s in any::<String>(), id in any::<u64>())| {
1258            let serialized = serialize(&WithReference { data: &s, id }).unwrap();
1259            let bincode_serialized = bincode::serialize(&WithReference { data: &s, id }).unwrap();
1260            prop_assert_eq!(&serialized, &bincode_serialized);
1261            let deserialized: WithReference = deserialize(&serialized).unwrap();
1262            let bincode_deserialized: WithReference = bincode::deserialize(&bincode_serialized).unwrap();
1263            prop_assert_eq!(deserialized, bincode_deserialized);
1264        });
1265    }
1266
1267    #[test]
1268    fn test_enum_equivalence() {
1269        #[derive(
1270            SchemaWrite,
1271            SchemaRead,
1272            Debug,
1273            PartialEq,
1274            Eq,
1275            serde::Serialize,
1276            serde::Deserialize,
1277            Clone,
1278            proptest_derive::Arbitrary,
1279        )]
1280        #[wincode(internal)]
1281        enum Enum {
1282            A { name: String, id: u64 },
1283            B(String, #[wincode(with = "containers::Vec<Pod<_>>")] Vec<u8>),
1284            C,
1285        }
1286
1287        proptest!(proptest_cfg(), |(e: Enum)| {
1288            let serialized = serialize(&e).unwrap();
1289            let bincode_serialized = bincode::serialize(&e).unwrap();
1290            prop_assert_eq!(&serialized, &bincode_serialized);
1291            let deserialized: Enum = deserialize(&serialized).unwrap();
1292            let bincode_deserialized: Enum = bincode::deserialize(&bincode_serialized).unwrap();
1293            prop_assert_eq!(deserialized, bincode_deserialized);
1294        });
1295    }
1296
1297    #[test]
1298    fn enum_with_tag_encoding_roundtrip() {
1299        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1300        #[wincode(internal, tag_encoding = "u8")]
1301        enum Enum {
1302            A { name: String, id: u64 },
1303            B(String, Vec<u8>),
1304            C,
1305        }
1306
1307        proptest!(proptest_cfg(), |(e: Enum)| {
1308            let serialized = serialize(&e).unwrap();
1309            let deserialized: Enum = deserialize(&serialized).unwrap();
1310            prop_assert_eq!(deserialized, e);
1311        });
1312    }
1313
1314    #[test]
1315    fn enum_with_custom_tag_roundtrip() {
1316        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1317        #[wincode(internal)]
1318        enum Enum {
1319            #[wincode(tag = 5)]
1320            A { name: String, id: u64 },
1321            #[wincode(tag = 8)]
1322            B(String, Vec<u8>),
1323            #[wincode(tag = 13)]
1324            C,
1325        }
1326
1327        proptest!(proptest_cfg(), |(e: Enum)| {
1328            let serialized = serialize(&e).unwrap();
1329            let deserialized: Enum = deserialize(&serialized).unwrap();
1330            prop_assert_eq!(deserialized, e);
1331        });
1332
1333        proptest!(proptest_cfg(), |(e: Enum)| {
1334            let serialized = serialize(&e).unwrap();
1335            let int: u32 = match e {
1336                Enum::A { .. } => 5,
1337                Enum::B(..) => 8,
1338                Enum::C => 13,
1339            };
1340            prop_assert_eq!(&int.to_le_bytes(), &serialized[..4]);
1341        });
1342    }
1343
1344    #[test]
1345    fn unit_enum_with_tag_encoding_static_size() {
1346        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq)]
1347        #[wincode(internal, tag_encoding = "u8")]
1348        enum Enum {
1349            A,
1350            B,
1351            C,
1352        }
1353
1354        assert!(matches!(
1355            <Enum as SchemaWrite>::TYPE_META,
1356            TypeMeta::Static {
1357                size: 1,
1358                zero_copy: false
1359            }
1360        ));
1361
1362        assert!(matches!(
1363            <Enum as SchemaRead<'_>>::TYPE_META,
1364            TypeMeta::Static {
1365                size: 1,
1366                zero_copy: false
1367            }
1368        ));
1369    }
1370
1371    #[test]
1372    fn unit_enum_with_static_size() {
1373        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq)]
1374        #[wincode(internal)]
1375        enum Enum {
1376            A,
1377            B,
1378            C,
1379        }
1380
1381        assert!(matches!(
1382            <Enum as SchemaWrite>::TYPE_META,
1383            TypeMeta::Static {
1384                size: 4,
1385                zero_copy: false
1386            }
1387        ));
1388
1389        assert!(matches!(
1390            <Enum as SchemaRead<'_>>::TYPE_META,
1391            TypeMeta::Static {
1392                size: 4,
1393                zero_copy: false
1394            }
1395        ));
1396    }
1397
1398    #[test]
1399    fn enum_tag_encoding() {
1400        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1401        #[wincode(internal, tag_encoding = "u8")]
1402        enum EnumU8 {
1403            A,
1404            B,
1405            C,
1406        }
1407
1408        proptest!(proptest_cfg(), |(e: EnumU8)| {
1409            let serialized = serialize(&e).unwrap();
1410            let int = e as u8;
1411            prop_assert_eq!(&int.to_le_bytes(), &serialized[..]);
1412        });
1413
1414        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1415        #[wincode(internal, tag_encoding = "u8")]
1416        enum EnumTupleU8 {
1417            A(u64),
1418            B(StructStatic),
1419            C(StructNonStatic),
1420        }
1421
1422        proptest!(proptest_cfg(), |(e: EnumTupleU8)| {
1423            let serialized = serialize(&e).unwrap();
1424            let int: u8 = match e {
1425                EnumTupleU8::A(_) => 0,
1426                EnumTupleU8::B(_) => 1,
1427                EnumTupleU8::C(_) => 2,
1428            };
1429            prop_assert_eq!(&int.to_le_bytes(), &serialized[..1]);
1430        });
1431
1432        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1433        #[wincode(internal, tag_encoding = "u8")]
1434        enum EnumRecordU8 {
1435            A { id: u64 },
1436            B { data: StructStatic },
1437            C { data: StructNonStatic },
1438        }
1439
1440        proptest!(proptest_cfg(), |(e: EnumRecordU8)| {
1441            let serialized = serialize(&e).unwrap();
1442            let int: u8 = match e {
1443                EnumRecordU8::A { .. } => 0,
1444                EnumRecordU8::B { .. } => 1,
1445                EnumRecordU8::C { .. } => 2,
1446            };
1447            prop_assert_eq!(&int.to_le_bytes(), &serialized[..1]);
1448        });
1449    }
1450
1451    #[test]
1452    fn enum_static_uniform_variants() {
1453        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1454        #[wincode(internal)]
1455        enum Enum {
1456            A {
1457                a: u64,
1458            },
1459            B {
1460                x: u32,
1461                y: u32,
1462            },
1463            C {
1464                a: u8,
1465                b: u8,
1466                c: u8,
1467                d: u8,
1468                e: u8,
1469                f: u8,
1470                g: u8,
1471                h: u8,
1472            },
1473        }
1474
1475        assert_eq!(
1476            <Enum as SchemaWrite>::TYPE_META,
1477            TypeMeta::Static {
1478                // (account for discriminant u32)
1479                size: 8 + 4,
1480                zero_copy: false
1481            }
1482        );
1483        assert_eq!(
1484            <Enum as SchemaRead<'_>>::TYPE_META,
1485            TypeMeta::Static {
1486                // (account for discriminant u32)
1487                size: 8 + 4,
1488                zero_copy: false
1489            }
1490        );
1491
1492        proptest!(proptest_cfg(), |(e: Enum)| {
1493            let serialized = serialize(&e).unwrap();
1494            let deserialized: Enum = deserialize(&serialized).unwrap();
1495            prop_assert_eq!(deserialized, e);
1496        });
1497    }
1498
1499    #[test]
1500    fn enum_dynamic_non_uniform_variants() {
1501        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1502        #[wincode(internal)]
1503        enum Enum {
1504            A { a: u64 },
1505            B { x: u32, y: u32 },
1506            C { a: u8, b: u8 },
1507        }
1508
1509        assert_eq!(<Enum as SchemaWrite>::TYPE_META, TypeMeta::Dynamic);
1510        assert_eq!(<Enum as SchemaRead<'_>>::TYPE_META, TypeMeta::Dynamic);
1511
1512        proptest!(proptest_cfg(), |(e: Enum)| {
1513            let serialized = serialize(&e).unwrap();
1514            let deserialized: Enum = deserialize(&serialized).unwrap();
1515            prop_assert_eq!(deserialized, e);
1516        });
1517    }
1518
1519    #[test]
1520    fn enum_single_variant_type_meta_pass_thru() {
1521        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, proptest_derive::Arbitrary)]
1522        #[wincode(internal)]
1523        enum Enum {
1524            A { a: u8, b: [u8; 32] },
1525        }
1526
1527        // Single variant enums should use the `TypeMeta` of the variant, but the zero-copy
1528        // flag should be `false`, due to the discriminant having potentially invalid bit patterns.
1529        assert_eq!(
1530            <Enum as SchemaWrite>::TYPE_META,
1531            TypeMeta::Static {
1532                size: 1 + 32 + 4,
1533                zero_copy: false
1534            }
1535        );
1536        assert_eq!(
1537            <Enum as SchemaRead<'_>>::TYPE_META,
1538            TypeMeta::Static {
1539                size: 1 + 32 + 4,
1540                zero_copy: false
1541            }
1542        );
1543    }
1544
1545    #[test]
1546    fn enum_unit_and_non_unit_dynamic() {
1547        #[derive(
1548            SchemaWrite,
1549            SchemaRead,
1550            Debug,
1551            PartialEq,
1552            proptest_derive::Arbitrary,
1553            serde::Serialize,
1554            serde::Deserialize,
1555        )]
1556        #[wincode(internal)]
1557        enum Enum {
1558            Unit,
1559            NonUnit(u8),
1560        }
1561
1562        assert_eq!(<Enum as SchemaWrite>::TYPE_META, TypeMeta::Dynamic);
1563        assert_eq!(<Enum as SchemaRead<'_>>::TYPE_META, TypeMeta::Dynamic);
1564
1565        proptest!(proptest_cfg(), |(e: Enum)| {
1566            let serialized = serialize(&e).unwrap();
1567            let bincode_serialized = bincode::serialize(&e).unwrap();
1568            prop_assert_eq!(&serialized, &bincode_serialized);
1569
1570            let deserialized: Enum = deserialize(&serialized).unwrap();
1571            let bincode_deserialized: Enum = bincode::deserialize(&bincode_serialized).unwrap();
1572            prop_assert_eq!(&deserialized, &bincode_deserialized);
1573            prop_assert_eq!(deserialized, e);
1574        });
1575    }
1576
1577    #[test]
1578    fn test_phantom_data() {
1579        let val = PhantomData::<StructStatic>;
1580        let serialized = serialize(&val).unwrap();
1581        let bincode_serialized = bincode::serialize(&val).unwrap();
1582        assert_eq!(&serialized, &bincode_serialized);
1583        assert_eq!(
1584            PhantomData::<StructStatic>::size_of(&val).unwrap(),
1585            bincode::serialized_size(&val).unwrap() as usize
1586        );
1587        let deserialized: PhantomData<StructStatic> = deserialize(&serialized).unwrap();
1588        let bincode_deserialized: PhantomData<StructStatic> =
1589            bincode::deserialize(&bincode_serialized).unwrap();
1590        assert_eq!(deserialized, bincode_deserialized);
1591    }
1592
1593    #[test]
1594    fn test_unit() {
1595        let serialized = serialize(&()).unwrap();
1596        let bincode_serialized = bincode::serialize(&()).unwrap();
1597        assert_eq!(&serialized, &bincode_serialized);
1598        assert_eq!(
1599            <()>::size_of(&()).unwrap(),
1600            bincode::serialized_size(&()).unwrap() as usize
1601        );
1602        assert!(deserialize::<()>(&serialized).is_ok());
1603        assert!(bincode::deserialize::<()>(&bincode_serialized).is_ok());
1604    }
1605
1606    #[test]
1607    fn test_borrowed_bytes() {
1608        #[derive(
1609            SchemaWrite, SchemaRead, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize,
1610        )]
1611        #[wincode(internal)]
1612        struct BorrowedBytes<'a> {
1613            bytes: &'a [u8],
1614        }
1615
1616        proptest!(proptest_cfg(), |(bytes in proptest::collection::vec(any::<u8>(), 0..=100))| {
1617            let val = BorrowedBytes { bytes: &bytes };
1618            let bincode_serialized = bincode::serialize(&val).unwrap();
1619            let schema_serialized = serialize(&val).unwrap();
1620            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1621            let bincode_deserialized: BorrowedBytes = bincode::deserialize(&bincode_serialized).unwrap();
1622            let schema_deserialized: BorrowedBytes = deserialize(&schema_serialized).unwrap();
1623            prop_assert_eq!(&val, &bincode_deserialized);
1624            prop_assert_eq!(val, schema_deserialized);
1625        });
1626    }
1627
1628    #[test]
1629    fn test_boxed_slice_pod_drop() {
1630        #[derive(proptest_derive::Arbitrary, Debug, Clone, Copy)]
1631        #[allow(dead_code)]
1632        struct Signature([u8; 64]);
1633
1634        type Target = containers::Box<[Pod<Signature>]>;
1635        proptest!(proptest_cfg(), |(slice in proptest::collection::vec(any::<Signature>(), 1..=32).prop_map(|vec| vec.into_boxed_slice()))| {
1636            let serialized = Target::serialize(&slice).unwrap();
1637            // Deliberately trigger the drop with a failed deserialization
1638            // This test is specifically to get miri to exercise the drop logic
1639            let deserialized = Target::deserialize(&serialized[..serialized.len() - 32]);
1640            prop_assert!(deserialized.is_err());
1641        });
1642    }
1643
1644    #[test]
1645    fn test_zero_copy_padding_disqualification() {
1646        #[derive(SchemaWrite, SchemaRead)]
1647        #[wincode(internal)]
1648        #[repr(C, align(4))]
1649        struct Padded {
1650            a: u8,
1651        }
1652
1653        assert!(matches!(
1654            <Padded as SchemaWrite>::TYPE_META,
1655            TypeMeta::Static {
1656                // Serialized size is still the size of the byte, not the in-memory size.
1657                size: 1,
1658                // Padding disqualifies the type from zero-copy optimization.
1659                zero_copy: false
1660            }
1661        ));
1662
1663        assert!(matches!(
1664            <Padded as SchemaRead<'_>>::TYPE_META,
1665            TypeMeta::Static {
1666                // Serialized size is still the size of the byte, not the in-memory size.
1667                size: 1,
1668                // Padding disqualifies the type from zero-copy optimization.
1669                zero_copy: false
1670            }
1671        ));
1672    }
1673
1674    proptest! {
1675        #![proptest_config(proptest_cfg())]
1676
1677        #[test]
1678        fn test_char(val in any::<char>()) {
1679            let bincode_serialized = bincode::serialize(&val).unwrap();
1680            let schema_serialized = serialize(&val).unwrap();
1681            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1682            prop_assert_eq!(char::size_of(&val).unwrap(), bincode::serialized_size(&val).unwrap() as usize);
1683
1684            let bincode_deserialized: char = bincode::deserialize(&bincode_serialized).unwrap();
1685            let schema_deserialized: char = deserialize(&schema_serialized).unwrap();
1686            prop_assert_eq!(val, bincode_deserialized);
1687            prop_assert_eq!(val, schema_deserialized);
1688        }
1689
1690        #[test]
1691        fn test_elem_compat(val in any::<StructStatic>()) {
1692            let bincode_serialized = bincode::serialize(&val).unwrap();
1693            let schema_serialized = <Elem<StructStatic>>::serialize(&val).unwrap();
1694            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1695
1696            let bincode_deserialized: StructStatic = bincode::deserialize(&bincode_serialized).unwrap();
1697            let schema_deserialized: StructStatic = <Elem<StructStatic>>::deserialize(&schema_serialized).unwrap();
1698            prop_assert_eq!(&val, &bincode_deserialized);
1699            prop_assert_eq!(val, schema_deserialized);
1700        }
1701
1702        #[test]
1703        fn test_elem_vec_compat(val in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
1704            let bincode_serialized = bincode::serialize(&val).unwrap();
1705            let schema_serialized = <containers::Vec<Elem<StructStatic>>>::serialize(&val).unwrap();
1706            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1707
1708            let bincode_deserialized: Vec<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
1709            let schema_deserialized = <containers::Vec<Elem<StructStatic>>>::deserialize(&schema_serialized).unwrap();
1710            prop_assert_eq!(&val, &bincode_deserialized);
1711            prop_assert_eq!(val, schema_deserialized);
1712        }
1713
1714        #[test]
1715        fn test_vec_elem_static(vec in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
1716            let bincode_serialized = bincode::serialize(&vec).unwrap();
1717            let schema_serialized = serialize(&vec).unwrap();
1718            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1719
1720            let bincode_deserialized: Vec<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
1721            let schema_deserialized: Vec<StructStatic> = deserialize(&schema_serialized).unwrap();
1722            prop_assert_eq!(&vec, &bincode_deserialized);
1723            prop_assert_eq!(vec, schema_deserialized);
1724        }
1725
1726        #[test]
1727        fn test_vec_elem_zero_copy(vec in proptest::collection::vec(any::<StructZeroCopy>(), 0..=100)) {
1728            let bincode_serialized = bincode::serialize(&vec).unwrap();
1729            let schema_serialized = serialize(&vec).unwrap();
1730            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1731
1732            let bincode_deserialized: Vec<StructZeroCopy> = bincode::deserialize(&bincode_serialized).unwrap();
1733            let schema_deserialized: Vec<StructZeroCopy> = deserialize(&schema_serialized).unwrap();
1734            prop_assert_eq!(&vec, &bincode_deserialized);
1735            prop_assert_eq!(vec, schema_deserialized);
1736        }
1737
1738
1739        #[test]
1740        fn test_vec_elem_non_static(vec in proptest::collection::vec(any::<StructNonStatic>(), 0..=16)) {
1741            let bincode_serialized = bincode::serialize(&vec).unwrap();
1742            let schema_serialized = serialize(&vec).unwrap();
1743            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1744
1745            let bincode_deserialized: Vec<StructNonStatic> = bincode::deserialize(&bincode_serialized).unwrap();
1746            let schema_deserialized: Vec<StructNonStatic> = deserialize(&schema_serialized).unwrap();
1747            prop_assert_eq!(&vec, &bincode_deserialized);
1748            prop_assert_eq!(vec, schema_deserialized);
1749        }
1750
1751        #[test]
1752        fn test_vec_elem_bytes(vec in proptest::collection::vec(any::<u8>(), 0..=100)) {
1753            let bincode_serialized = bincode::serialize(&vec).unwrap();
1754            let schema_serialized = serialize(&vec).unwrap();
1755            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1756
1757            let bincode_deserialized: Vec<u8> = bincode::deserialize(&bincode_serialized).unwrap();
1758            let schema_deserialized: Vec<u8> = deserialize(&schema_serialized).unwrap();
1759            prop_assert_eq!(&vec, &bincode_deserialized);
1760            prop_assert_eq!(vec, schema_deserialized);
1761        }
1762
1763        #[test]
1764        fn test_serialize_slice(slice in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
1765            let bincode_serialized = bincode::serialize(slice.as_slice()).unwrap();
1766            let schema_serialized = serialize(slice.as_slice()).unwrap();
1767            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1768        }
1769
1770        #[test]
1771        fn test_vec_pod(vec in proptest::collection::vec(any::<[u8; 32]>(), 0..=100)) {
1772            let bincode_serialized = bincode::serialize(&vec).unwrap();
1773            let schema_serialized = serialize(&vec).unwrap();
1774            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1775
1776            let bincode_deserialized: Vec<[u8; 32]> = bincode::deserialize(&bincode_serialized).unwrap();
1777            let schema_deserialized: Vec<[u8; 32]> = deserialize(&schema_serialized).unwrap();
1778            prop_assert_eq!(&vec, &bincode_deserialized);
1779            prop_assert_eq!(vec, schema_deserialized);
1780        }
1781
1782        #[test]
1783        fn test_vec_deque_elem_static(vec in proptest::collection::vec_deque(any::<StructStatic>(), 0..=100)) {
1784            let bincode_serialized = bincode::serialize(&vec).unwrap();
1785            let schema_serialized = serialize(&vec).unwrap();
1786            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1787
1788            let bincode_deserialized: VecDeque<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
1789            let schema_deserialized: VecDeque<StructStatic> = deserialize(&schema_serialized).unwrap();
1790            prop_assert_eq!(&vec, &bincode_deserialized);
1791            prop_assert_eq!(vec, schema_deserialized);
1792        }
1793
1794        #[test]
1795        fn test_vec_deque_elem_non_static(vec in proptest::collection::vec_deque(any::<StructNonStatic>(), 0..=16)) {
1796            let bincode_serialized = bincode::serialize(&vec).unwrap();
1797            let schema_serialized = serialize(&vec).unwrap();
1798            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1799
1800            let bincode_deserialized: VecDeque<StructNonStatic> = bincode::deserialize(&bincode_serialized).unwrap();
1801            let schema_deserialized: VecDeque<StructNonStatic> = deserialize(&schema_serialized).unwrap();
1802            prop_assert_eq!(&vec, &bincode_deserialized);
1803            prop_assert_eq!(vec, schema_deserialized);
1804        }
1805
1806        #[test]
1807        fn test_vec_deque_elem_bytes(vec in proptest::collection::vec_deque(any::<u8>(), 0..=100)) {
1808            let bincode_serialized = bincode::serialize(&vec).unwrap();
1809            let schema_serialized = serialize(&vec).unwrap();
1810            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1811
1812            let bincode_deserialized: VecDeque<u8> = bincode::deserialize(&bincode_serialized).unwrap();
1813            let schema_deserialized: VecDeque<u8> = deserialize(&schema_serialized).unwrap();
1814            prop_assert_eq!(&vec, &bincode_deserialized);
1815            prop_assert_eq!(vec, schema_deserialized);
1816        }
1817
1818        #[test]
1819        fn test_hash_map_zero_copy(map in proptest::collection::hash_map(any::<u8>(), any::<StructZeroCopy>(), 0..=100)) {
1820            let bincode_serialized = bincode::serialize(&map).unwrap();
1821            let schema_serialized = serialize(&map).unwrap();
1822            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1823
1824            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1825            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1826            prop_assert_eq!(&map, &bincode_deserialized);
1827            prop_assert_eq!(map, schema_deserialized);
1828        }
1829
1830        #[test]
1831        fn test_hash_map_static(map in proptest::collection::hash_map(any::<u64>(), any::<StructStatic>(), 0..=100)) {
1832            let bincode_serialized = bincode::serialize(&map).unwrap();
1833            let schema_serialized = serialize(&map).unwrap();
1834            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1835
1836            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1837            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1838            prop_assert_eq!(&map, &bincode_deserialized);
1839            prop_assert_eq!(map, schema_deserialized);
1840        }
1841
1842
1843        #[test]
1844        fn test_hash_map_non_static(map in proptest::collection::hash_map(any::<u64>(), any::<StructNonStatic>(), 0..=16)) {
1845            let bincode_serialized = bincode::serialize(&map).unwrap();
1846            let schema_serialized = serialize(&map).unwrap();
1847            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1848
1849            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1850            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1851            prop_assert_eq!(&map, &bincode_deserialized);
1852            prop_assert_eq!(map, schema_deserialized);
1853        }
1854
1855        #[test]
1856        fn test_hash_set_zero_copy(set in proptest::collection::hash_set(any::<StructZeroCopy>(), 0..=100)) {
1857            let bincode_serialized = bincode::serialize(&set).unwrap();
1858            let schema_serialized = serialize(&set).unwrap();
1859            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1860
1861            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1862            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1863            prop_assert_eq!(&set, &bincode_deserialized);
1864            prop_assert_eq!(set, schema_deserialized);
1865        }
1866
1867        #[test]
1868        fn test_hash_set_static(set in proptest::collection::hash_set(any::<StructStatic>(), 0..=100)) {
1869            let bincode_serialized = bincode::serialize(&set).unwrap();
1870            let schema_serialized = serialize(&set).unwrap();
1871            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1872
1873            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1874            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1875            prop_assert_eq!(&set, &bincode_deserialized);
1876            prop_assert_eq!(set, schema_deserialized);
1877        }
1878
1879        #[test]
1880        fn test_hash_set_non_static(set in proptest::collection::hash_set(any::<StructNonStatic>(), 0..=16)) {
1881            let bincode_serialized = bincode::serialize(&set).unwrap();
1882            let schema_serialized = serialize(&set).unwrap();
1883            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1884
1885            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1886            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1887            prop_assert_eq!(&set, &bincode_deserialized);
1888            prop_assert_eq!(set, schema_deserialized);
1889        }
1890
1891        #[test]
1892        fn test_btree_map_zero_copy(map in proptest::collection::btree_map(any::<u8>(), any::<StructZeroCopy>(), 0..=100)) {
1893            let bincode_serialized = bincode::serialize(&map).unwrap();
1894            let schema_serialized = serialize(&map).unwrap();
1895            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1896
1897            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1898            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1899            prop_assert_eq!(&map, &bincode_deserialized);
1900            prop_assert_eq!(map, schema_deserialized);
1901        }
1902
1903        #[test]
1904        fn test_btree_map_static(map in proptest::collection::btree_map(any::<u64>(), any::<StructStatic>(), 0..=100)) {
1905            let bincode_serialized = bincode::serialize(&map).unwrap();
1906            let schema_serialized = serialize(&map).unwrap();
1907            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1908
1909            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1910            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1911            prop_assert_eq!(&map, &bincode_deserialized);
1912            prop_assert_eq!(map, schema_deserialized);
1913        }
1914
1915        #[test]
1916        fn test_btree_map_non_static(map in proptest::collection::btree_map(any::<u64>(), any::<StructNonStatic>(), 0..=16)) {
1917            let bincode_serialized = bincode::serialize(&map).unwrap();
1918            let schema_serialized = serialize(&map).unwrap();
1919            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1920
1921            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1922            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1923            prop_assert_eq!(&map, &bincode_deserialized);
1924            prop_assert_eq!(map, schema_deserialized);
1925        }
1926
1927        #[test]
1928        fn test_btree_set_zero_copy(set in proptest::collection::btree_set(any::<StructZeroCopy>(), 0..=100)) {
1929            let bincode_serialized = bincode::serialize(&set).unwrap();
1930            let schema_serialized = serialize(&set).unwrap();
1931            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1932
1933            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1934            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1935            prop_assert_eq!(&set, &bincode_deserialized);
1936            prop_assert_eq!(set, schema_deserialized);
1937        }
1938
1939        #[test]
1940        fn test_btree_set_static(set in proptest::collection::btree_set(any::<StructStatic>(), 0..=100)) {
1941            let bincode_serialized = bincode::serialize(&set).unwrap();
1942            let schema_serialized = serialize(&set).unwrap();
1943            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1944
1945            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1946            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1947            prop_assert_eq!(&set, &bincode_deserialized);
1948            prop_assert_eq!(set, schema_deserialized);
1949        }
1950
1951        #[test]
1952        fn test_btree_set_non_static(map in proptest::collection::btree_set(any::<StructNonStatic>(), 0..=16)) {
1953            let bincode_serialized = bincode::serialize(&map).unwrap();
1954            let schema_serialized = serialize(&map).unwrap();
1955            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1956
1957            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
1958            let schema_deserialized = deserialize(&schema_serialized).unwrap();
1959            prop_assert_eq!(&map, &bincode_deserialized);
1960            prop_assert_eq!(map, schema_deserialized);
1961        }
1962
1963        #[test]
1964        fn test_binary_heap_zero_copy(heap in proptest::collection::binary_heap(any::<StructZeroCopy>(), 0..=100)) {
1965            let bincode_serialized = bincode::serialize(&heap).unwrap();
1966            let schema_serialized = serialize(&heap).unwrap();
1967            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1968
1969            let bincode_deserialized: BinaryHeap<StructZeroCopy> = bincode::deserialize(&bincode_serialized).unwrap();
1970            let schema_deserialized: BinaryHeap<StructZeroCopy> = deserialize(&schema_serialized).unwrap();
1971            prop_assert_eq!(heap.as_slice(), bincode_deserialized.as_slice());
1972            prop_assert_eq!(heap.as_slice(), schema_deserialized.as_slice());
1973        }
1974
1975        #[test]
1976        fn test_binary_heap_static(heap in proptest::collection::binary_heap(any::<StructStatic>(), 0..=100)) {
1977            let bincode_serialized = bincode::serialize(&heap).unwrap();
1978            let schema_serialized = serialize(&heap).unwrap();
1979            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1980
1981            let bincode_deserialized: BinaryHeap<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
1982            let schema_deserialized: BinaryHeap<StructStatic> = deserialize(&schema_serialized).unwrap();
1983            prop_assert_eq!(heap.as_slice(), bincode_deserialized.as_slice());
1984            prop_assert_eq!(heap.as_slice(), schema_deserialized.as_slice());
1985        }
1986
1987
1988        #[test]
1989        fn test_binary_heap_non_static(heap in proptest::collection::binary_heap(any::<StructNonStatic>(), 0..=16)) {
1990            let bincode_serialized = bincode::serialize(&heap).unwrap();
1991            let schema_serialized = serialize(&heap).unwrap();
1992            prop_assert_eq!(&bincode_serialized, &schema_serialized);
1993
1994            let bincode_deserialized: BinaryHeap<StructNonStatic> = bincode::deserialize(&bincode_serialized).unwrap();
1995            let schema_deserialized: BinaryHeap<StructNonStatic> = deserialize(&schema_serialized).unwrap();
1996            prop_assert_eq!(heap.as_slice(), bincode_deserialized.as_slice());
1997            prop_assert_eq!(heap.as_slice(), schema_deserialized.as_slice());
1998        }
1999
2000        #[test]
2001        fn test_linked_list_zero_copy(list in proptest::collection::linked_list(any::<StructZeroCopy>(), 0..=100)) {
2002            let bincode_serialized = bincode::serialize(&list).unwrap();
2003            let schema_serialized = serialize(&list).unwrap();
2004            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2005
2006            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2007            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2008            prop_assert_eq!(&list, &bincode_deserialized);
2009            prop_assert_eq!(list, schema_deserialized);
2010        }
2011
2012        #[test]
2013        fn test_linked_list_static(list in proptest::collection::linked_list(any::<StructStatic>(), 0..=100)) {
2014            let bincode_serialized = bincode::serialize(&list).unwrap();
2015            let schema_serialized = serialize(&list).unwrap();
2016            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2017
2018            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2019            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2020            prop_assert_eq!(&list, &bincode_deserialized);
2021            prop_assert_eq!(list, schema_deserialized);
2022        }
2023
2024        #[test]
2025        fn test_linked_list_non_static(list in proptest::collection::linked_list(any::<StructNonStatic>(), 0..=16)) {
2026            let bincode_serialized = bincode::serialize(&list).unwrap();
2027            let schema_serialized = serialize(&list).unwrap();
2028            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2029
2030            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2031            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2032            prop_assert_eq!(&list, &bincode_deserialized);
2033            prop_assert_eq!(list, schema_deserialized);
2034        }
2035
2036        #[test]
2037        fn test_array_bytes(array in any::<[u8; 32]>()) {
2038            let bincode_serialized = bincode::serialize(&array).unwrap();
2039            let schema_serialized = serialize(&array).unwrap();
2040            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2041
2042            let bincode_deserialized: [u8; 32] = bincode::deserialize(&bincode_serialized).unwrap();
2043            let schema_deserialized: [u8; 32] = deserialize(&schema_serialized).unwrap();
2044            prop_assert_eq!(&array, &bincode_deserialized);
2045            prop_assert_eq!(array, schema_deserialized);
2046        }
2047
2048        #[test]
2049        fn test_array_static(array in any::<[u64; 32]>()) {
2050            let bincode_serialized = bincode::serialize(&array).unwrap();
2051            type Target = [u64; 32];
2052            let schema_serialized = Target::serialize(&array).unwrap();
2053            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2054            let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
2055            let schema_deserialized: Target = deserialize(&schema_serialized).unwrap();
2056            prop_assert_eq!(&array, &bincode_deserialized);
2057            prop_assert_eq!(array, schema_deserialized);
2058        }
2059
2060        #[test]
2061        fn test_array_non_static(array in any::<[StructNonStatic; 16]>()) {
2062            let bincode_serialized = bincode::serialize(&array).unwrap();
2063            type Target = [StructNonStatic; 16];
2064            let schema_serialized = Target::serialize(&array).unwrap();
2065            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2066            let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
2067            let schema_deserialized: Target = deserialize(&schema_serialized).unwrap();
2068            prop_assert_eq!(&array, &bincode_deserialized);
2069            prop_assert_eq!(array, schema_deserialized);
2070        }
2071
2072        #[test]
2073        fn test_option(option in proptest::option::of(any::<StructStatic>())) {
2074            let bincode_serialized = bincode::serialize(&option).unwrap();
2075            let schema_serialized = serialize(&option).unwrap();
2076
2077            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2078            let bincode_deserialized: Option<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
2079            let schema_deserialized: Option<StructStatic> = deserialize(&schema_serialized).unwrap();
2080            prop_assert_eq!(&option, &bincode_deserialized);
2081            prop_assert_eq!(&option, &schema_deserialized);
2082        }
2083
2084        #[test]
2085        fn test_option_container(option in proptest::option::of(any::<[u8; 32]>())) {
2086            let bincode_serialized = bincode::serialize(&option).unwrap();
2087            type Target = Option<Pod<[u8; 32]>>;
2088            let schema_serialized = Target::serialize(&option).unwrap();
2089            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2090            let bincode_deserialized: Option<[u8; 32]> = bincode::deserialize(&bincode_serialized).unwrap();
2091            let schema_deserialized: Option<[u8; 32]> = Target::deserialize(&schema_serialized).unwrap();
2092            prop_assert_eq!(&option, &bincode_deserialized);
2093            prop_assert_eq!(&option, &schema_deserialized);
2094        }
2095
2096        #[test]
2097        fn test_bool(val in any::<bool>()) {
2098            let bincode_serialized = bincode::serialize(&val).unwrap();
2099            let schema_serialized = serialize(&val).unwrap();
2100            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2101            let bincode_deserialized: bool = bincode::deserialize(&bincode_serialized).unwrap();
2102            let schema_deserialized: bool = deserialize(&schema_serialized).unwrap();
2103            prop_assert_eq!(val, bincode_deserialized);
2104            prop_assert_eq!(val, schema_deserialized);
2105        }
2106
2107        #[test]
2108        fn test_bool_invalid_bit_pattern(val in 2u8..=255) {
2109            let bincode_deserialized: Result<bool,_> = bincode::deserialize(&[val]);
2110            let schema_deserialized: Result<bool,_> = deserialize(&[val]);
2111            prop_assert!(bincode_deserialized.is_err());
2112            prop_assert!(schema_deserialized.is_err());
2113        }
2114
2115        #[test]
2116        fn test_box(s in any::<StructStatic>()) {
2117            let data = Box::new(s);
2118            let bincode_serialized = bincode::serialize(&data).unwrap();
2119            let schema_serialized = serialize(&data).unwrap();
2120            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2121
2122            let bincode_deserialized: Box<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
2123            let schema_deserialized: Box<StructStatic> = deserialize(&schema_serialized).unwrap();
2124            prop_assert_eq!(&data, &bincode_deserialized);
2125            prop_assert_eq!(&data, &schema_deserialized);
2126        }
2127
2128        #[test]
2129        fn test_rc(s in any::<StructStatic>()) {
2130            let data = Rc::new(s);
2131            let bincode_serialized = bincode::serialize(&data).unwrap();
2132            let schema_serialized = serialize(&data).unwrap();
2133            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2134
2135            let bincode_deserialized: Rc<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
2136            let schema_deserialized: Rc<StructStatic> = deserialize(&schema_serialized).unwrap();
2137            prop_assert_eq!(&data, &bincode_deserialized);
2138            prop_assert_eq!(&data, &schema_deserialized);
2139        }
2140
2141        #[test]
2142        fn test_arc(s in any::<StructStatic>()) {
2143            let data = Arc::new(s);
2144            let bincode_serialized = bincode::serialize(&data).unwrap();
2145            let schema_serialized = serialize(&data).unwrap();
2146            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2147
2148            let bincode_deserialized: Arc<StructStatic> = bincode::deserialize(&bincode_serialized).unwrap();
2149            let schema_deserialized: Arc<StructStatic> = deserialize(&schema_serialized).unwrap();
2150            prop_assert_eq!(&data, &bincode_deserialized);
2151            prop_assert_eq!(&data, &schema_deserialized);
2152        }
2153
2154        #[test]
2155        fn test_boxed_slice_zero_copy(vec in proptest::collection::vec(any::<StructZeroCopy>(), 0..=100)) {
2156            let data = vec.into_boxed_slice();
2157            let bincode_serialized = bincode::serialize(&data).unwrap();
2158            let schema_serialized = serialize(&data).unwrap();
2159            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2160
2161            let bincode_deserialized: Box<[StructZeroCopy]> = bincode::deserialize(&bincode_serialized).unwrap();
2162            let schema_deserialized: Box<[StructZeroCopy]> = deserialize(&schema_serialized).unwrap();
2163            prop_assert_eq!(&data, &bincode_deserialized);
2164            prop_assert_eq!(&data, &schema_deserialized);
2165        }
2166
2167        #[test]
2168        fn test_boxed_slice_static(vec in proptest::collection::vec(any::<StructStatic>(), 0..=100)) {
2169            let data = vec.into_boxed_slice();
2170            let bincode_serialized = bincode::serialize(&data).unwrap();
2171            let schema_serialized = serialize(&data).unwrap();
2172            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2173
2174            let bincode_deserialized: Box<[StructStatic]> = bincode::deserialize(&bincode_serialized).unwrap();
2175            let schema_deserialized: Box<[StructStatic]> = deserialize(&schema_serialized).unwrap();
2176            prop_assert_eq!(&data, &bincode_deserialized);
2177            prop_assert_eq!(&data, &schema_deserialized);
2178        }
2179
2180        #[test]
2181        fn test_boxed_slice_non_static(vec in proptest::collection::vec(any::<StructNonStatic>(), 0..=16)) {
2182            let data = vec.into_boxed_slice();
2183            let bincode_serialized = bincode::serialize(&data).unwrap();
2184            type Target = Box<[StructNonStatic]>;
2185            let schema_serialized = serialize(&data).unwrap();
2186            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2187
2188            let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
2189            let schema_deserialized: Target = Target::deserialize(&schema_serialized).unwrap();
2190            prop_assert_eq!(&data, &bincode_deserialized);
2191            prop_assert_eq!(&data, &schema_deserialized);
2192        }
2193
2194        #[test]
2195        fn test_integers(
2196            val in (
2197                any::<u8>(),
2198                any::<i8>(),
2199                any::<u16>(),
2200                any::<i16>(),
2201                any::<u32>(),
2202                any::<i32>(),
2203                any::<usize>(),
2204                any::<isize>(),
2205                any::<u64>(),
2206                any::<i64>(),
2207                any::<u128>(),
2208                any::<i128>()
2209            )
2210        ) {
2211            type Target = (u8, i8, u16, i16, u32, i32, usize, isize, u64, i64, u128, i128);
2212            let bincode_serialized = bincode::serialize(&val).unwrap();
2213            let schema_serialized = serialize(&val).unwrap();
2214            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2215            let bincode_deserialized: Target = bincode::deserialize(&bincode_serialized).unwrap();
2216            let schema_deserialized: Target = deserialize(&schema_serialized).unwrap();
2217            prop_assert_eq!(val, bincode_deserialized);
2218            prop_assert_eq!(val, schema_deserialized);
2219        }
2220
2221        #[test]
2222        fn test_tuple_zero_copy(
2223            tuple in (
2224                any::<StructZeroCopy>(),
2225                any::<[u8; 32]>(),
2226            )
2227        ) {
2228            let bincode_serialized = bincode::serialize(&tuple).unwrap();
2229            let schema_serialized = serialize(&tuple).unwrap();
2230
2231            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2232            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2233            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2234            prop_assert_eq!(&tuple, &bincode_deserialized);
2235            prop_assert_eq!(&tuple, &schema_deserialized);
2236
2237        }
2238
2239        #[test]
2240        fn test_tuple_static(
2241            tuple in (
2242                any::<StructStatic>(),
2243                any::<[u8; 32]>(),
2244            )
2245        ) {
2246            let bincode_serialized = bincode::serialize(&tuple).unwrap();
2247            let schema_serialized = serialize(&tuple).unwrap();
2248
2249            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2250            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2251            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2252            prop_assert_eq!(&tuple, &bincode_deserialized);
2253            prop_assert_eq!(&tuple, &schema_deserialized);
2254
2255        }
2256
2257        #[test]
2258        fn test_tuple_non_static(
2259            tuple in (
2260                any::<StructNonStatic>(),
2261                any::<[u8; 32]>(),
2262                proptest::collection::vec(any::<StructStatic>(), 0..=100),
2263            )
2264        ) {
2265            let bincode_serialized = bincode::serialize(&tuple).unwrap();
2266            type BincodeTarget = (StructNonStatic, [u8; 32], Vec<StructStatic>);
2267            type Target = (StructNonStatic, Pod<[u8; 32]>, Vec<StructStatic>);
2268            let schema_serialized = Target::serialize(&tuple).unwrap();
2269
2270            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2271            let bincode_deserialized: BincodeTarget = bincode::deserialize(&bincode_serialized).unwrap();
2272            let schema_deserialized = Target::deserialize(&schema_serialized).unwrap();
2273            prop_assert_eq!(&tuple, &bincode_deserialized);
2274            prop_assert_eq!(&tuple, &schema_deserialized);
2275
2276        }
2277
2278        #[test]
2279        fn test_str(str in any::<String>()) {
2280            let bincode_serialized = bincode::serialize(&str).unwrap();
2281            let schema_serialized = serialize(&str).unwrap();
2282            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2283            let bincode_deserialized: &str = bincode::deserialize(&bincode_serialized).unwrap();
2284            let schema_deserialized: &str = deserialize(&schema_serialized).unwrap();
2285            prop_assert_eq!(&str, &bincode_deserialized);
2286            prop_assert_eq!(&str, &schema_deserialized);
2287
2288            let bincode_deserialized: String = bincode::deserialize(&bincode_serialized).unwrap();
2289            let schema_deserialized: String = deserialize(&schema_serialized).unwrap();
2290            prop_assert_eq!(&str, &bincode_deserialized);
2291            prop_assert_eq!(&str, &schema_deserialized);
2292        }
2293
2294        #[test]
2295        fn test_struct_zero_copy(val in any::<StructZeroCopy>()) {
2296            let bincode_serialized = bincode::serialize(&val).unwrap();
2297            let schema_serialized = serialize(&val).unwrap();
2298            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2299
2300            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2301            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2302            prop_assert_eq!(&val, &bincode_deserialized);
2303            prop_assert_eq!(&val, &schema_deserialized);
2304        }
2305
2306        #[test]
2307        fn test_struct_static(val in any::<StructStatic>()) {
2308            let bincode_serialized = bincode::serialize(&val).unwrap();
2309            let schema_serialized = serialize(&val).unwrap();
2310            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2311
2312            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2313            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2314            prop_assert_eq!(&val, &bincode_deserialized);
2315            prop_assert_eq!(&val, &schema_deserialized);
2316        }
2317
2318        #[test]
2319        fn test_struct_non_static(val in any::<StructNonStatic>()) {
2320            let bincode_serialized = bincode::serialize(&val).unwrap();
2321            let schema_serialized = serialize(&val).unwrap();
2322            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2323
2324            let bincode_deserialized = bincode::deserialize(&bincode_serialized).unwrap();
2325            let schema_deserialized = deserialize(&schema_serialized).unwrap();
2326            prop_assert_eq!(&val, &bincode_deserialized);
2327            prop_assert_eq!(&val, &schema_deserialized);
2328        }
2329
2330        #[test]
2331        fn test_floats(
2332            val in (
2333                any::<f32>(),
2334                any::<f64>(),
2335            )
2336        ) {
2337            let bincode_serialized = bincode::serialize(&val).unwrap();
2338            let schema_serialized = serialize(&val).unwrap();
2339            prop_assert_eq!(&bincode_serialized, &schema_serialized);
2340
2341            let bincode_deserialized: (f32, f64) = bincode::deserialize(&bincode_serialized).unwrap();
2342            let schema_deserialized: (f32, f64) = deserialize(&schema_serialized).unwrap();
2343            prop_assert_eq!(val, bincode_deserialized);
2344            prop_assert_eq!(val, schema_deserialized);
2345        }
2346    }
2347
2348    #[test]
2349    fn test_struct_zero_copy_refs() {
2350        // Owned zero-copy type.
2351        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
2352        #[wincode(internal)]
2353        #[repr(C)]
2354        struct Zc {
2355            a: u8,
2356            b: [u8; 64],
2357            c: i8,
2358            d: [i8; 64],
2359        }
2360
2361        // `Zc`, mirrored with references.
2362        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
2363        #[wincode(internal)]
2364        #[repr(C)]
2365        struct ZcRefs<'a> {
2366            a: &'a u8,
2367            b: &'a [u8; 64],
2368            c: &'a i8,
2369            d: &'a [i8; 64],
2370        }
2371
2372        // `Zc`, wrapped in a reference.
2373        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
2374        #[wincode(internal)]
2375        #[repr(transparent)]
2376        struct ZcWrapper<'a> {
2377            data: &'a Zc,
2378        }
2379
2380        impl<'a> From<&'a ZcRefs<'a>> for Zc {
2381            fn from(value: &'a ZcRefs<'a>) -> Self {
2382                Self {
2383                    a: *value.a,
2384                    b: *value.b,
2385                    c: *value.c,
2386                    d: *value.d,
2387                }
2388            }
2389        }
2390
2391        proptest!(proptest_cfg(), |(data in any::<Zc>())| {
2392            let serialized = serialize(&data).unwrap();
2393            let deserialized = Zc::deserialize(&serialized).unwrap();
2394            assert_eq!(data, deserialized);
2395
2396            let serialized_ref = serialize(&ZcRefs { a: &data.a, b: &data.b, c: &data.c, d: &data.d }).unwrap();
2397            assert_eq!(serialized_ref, serialized);
2398            let deserialized_ref = ZcRefs::deserialize(&serialized_ref).unwrap();
2399            assert_eq!(data, (&deserialized_ref).into());
2400
2401            let serialized_wrapper = serialize(&ZcWrapper { data: &data }).unwrap();
2402            assert_eq!(serialized_wrapper, serialized);
2403            let deserialized_wrapper = ZcWrapper::deserialize(&serialized_wrapper).unwrap();
2404            assert_eq!(data, *deserialized_wrapper.data);
2405        });
2406    }
2407
2408    #[test]
2409    fn test_pod_zero_copy() {
2410        #[derive(Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy)]
2411        #[repr(transparent)]
2412        struct Address([u8; 64]);
2413
2414        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
2415        #[wincode(internal)]
2416        #[repr(C)]
2417        struct MyStruct {
2418            #[wincode(with = "Pod<_>")]
2419            address: Address,
2420        }
2421
2422        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
2423        #[wincode(internal)]
2424        struct MyStructRef<'a> {
2425            inner: &'a MyStruct,
2426        }
2427
2428        proptest!(proptest_cfg(), |(data in any::<MyStruct>())| {
2429            let serialized = serialize(&data).unwrap();
2430            let deserialized = MyStruct::deserialize(&serialized).unwrap();
2431            assert_eq!(data, deserialized);
2432
2433            let serialized_ref = serialize(&MyStructRef { inner: &data }).unwrap();
2434            assert_eq!(serialized_ref, serialized);
2435            let deserialized_ref = MyStructRef::deserialize(&serialized_ref).unwrap();
2436            assert_eq!(data, *deserialized_ref.inner);
2437        });
2438    }
2439
2440    #[test]
2441    fn test_pod_zero_copy_explicit_ref() {
2442        #[derive(Debug, PartialEq, Eq, proptest_derive::Arbitrary, Clone, Copy)]
2443        #[repr(transparent)]
2444        struct Address([u8; 64]);
2445
2446        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq)]
2447        #[wincode(internal)]
2448        struct MyStructRef<'a> {
2449            #[wincode(with = "&'a Pod<Address>")]
2450            address: &'a Address,
2451        }
2452
2453        #[derive(SchemaWrite, SchemaRead, Debug, PartialEq, Eq, proptest_derive::Arbitrary)]
2454        #[wincode(internal)]
2455        struct MyStruct {
2456            #[wincode(with = "Pod<_>")]
2457            address: Address,
2458        }
2459
2460        proptest!(proptest_cfg(), |(data in any::<MyStruct>())| {
2461            let serialized = serialize(&data).unwrap();
2462            let deserialized = MyStruct::deserialize(&serialized).unwrap();
2463            assert_eq!(data, deserialized);
2464
2465            let serialized_ref = serialize(&MyStructRef { address: &data.address }).unwrap();
2466            assert_eq!(serialized_ref, serialized);
2467            let deserialized_ref = MyStructRef::deserialize(&serialized_ref).unwrap();
2468            assert_eq!(data.address, *deserialized_ref.address);
2469        });
2470    }
2471
2472    #[test]
2473    fn test_result_basic() {
2474        proptest!(proptest_cfg(), |(value: Result<u64, String>)| {
2475            let wincode_serialized = serialize(&value).unwrap();
2476            let bincode_serialized = bincode::serialize(&value).unwrap();
2477            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
2478
2479            let wincode_deserialized: Result<u64, String> = deserialize(&wincode_serialized).unwrap();
2480            let bincode_deserialized: Result<u64, String> = bincode::deserialize(&bincode_serialized).unwrap();
2481            prop_assert_eq!(&value, &wincode_deserialized);
2482            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
2483        });
2484    }
2485
2486    #[test]
2487    fn test_result_bincode_equivalence() {
2488        use serde::{Deserialize, Serialize};
2489
2490        #[derive(
2491            Serialize,
2492            Deserialize,
2493            Debug,
2494            PartialEq,
2495            Clone,
2496            proptest_derive::Arbitrary,
2497            SchemaWrite,
2498            SchemaRead,
2499        )]
2500        #[wincode(internal)]
2501        enum Error {
2502            NotFound,
2503            InvalidInput(String),
2504            Other(u32),
2505        }
2506
2507        proptest!(proptest_cfg(), |(value: Result<Vec<u8>, Error>)| {
2508            let wincode_serialized = serialize(&value).unwrap();
2509            let bincode_serialized = bincode::serialize(&value).unwrap();
2510            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
2511
2512            let wincode_deserialized: Result<Vec<u8>, Error> = deserialize(&wincode_serialized).unwrap();
2513            let bincode_deserialized: Result<Vec<u8>, Error> = bincode::deserialize(&bincode_serialized).unwrap();
2514            prop_assert_eq!(&value, &wincode_deserialized);
2515            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
2516        });
2517    }
2518
2519    #[test]
2520    fn test_result_nested() {
2521        proptest!(proptest_cfg(), |(value: Result<Result<u64, String>, u32>)| {
2522            let wincode_serialized = serialize(&value).unwrap();
2523            let bincode_serialized = bincode::serialize(&value).unwrap();
2524            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
2525
2526            let wincode_deserialized: Result<Result<u64, String>, u32> = deserialize(&wincode_serialized).unwrap();
2527            let bincode_deserialized: Result<Result<u64, String>, u32> = bincode::deserialize(&bincode_serialized).unwrap();
2528            prop_assert_eq!(&value, &wincode_deserialized);
2529            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
2530        });
2531    }
2532
2533    #[test]
2534    fn test_result_with_complex_types() {
2535        use std::collections::HashMap;
2536
2537        proptest!(proptest_cfg(), |(value: Result<HashMap<String, Vec<u32>>, bool>)| {
2538            let wincode_serialized = serialize(&value).unwrap();
2539            let bincode_serialized = bincode::serialize(&value).unwrap();
2540            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
2541
2542            let wincode_deserialized: Result<HashMap<String, Vec<u32>>, bool> = deserialize(&wincode_serialized).unwrap();
2543            let bincode_deserialized: Result<HashMap<String, Vec<u32>>, bool> = bincode::deserialize(&bincode_serialized).unwrap();
2544            prop_assert_eq!(&value, &wincode_deserialized);
2545            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
2546        });
2547    }
2548
2549    #[test]
2550    fn test_result_type_meta_static() {
2551        // Result<u64, u64> should be TypeMeta::Static because both T and E are Static with equal sizes
2552        assert!(matches!(
2553            <Result<u64, u64> as SchemaRead>::TYPE_META,
2554            TypeMeta::Static {
2555                size: 12,
2556                zero_copy: false
2557            }
2558        ));
2559
2560        proptest!(proptest_cfg(), |(value: Result<u64, u64>)| {
2561            let wincode_serialized = serialize(&value).unwrap();
2562            let bincode_serialized = bincode::serialize(&value).unwrap();
2563            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
2564
2565            let wincode_deserialized: Result<u64, u64> = deserialize(&wincode_serialized).unwrap();
2566            let bincode_deserialized: Result<u64, u64> = bincode::deserialize(&bincode_serialized).unwrap();
2567            prop_assert_eq!(&value, &wincode_deserialized);
2568            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
2569        });
2570    }
2571
2572    #[test]
2573    fn test_result_type_meta_dynamic() {
2574        // Result<u64, String> should be TypeMeta::Dynamic because String is Dynamic
2575        assert!(matches!(
2576            <Result<u64, String> as SchemaRead>::TYPE_META,
2577            TypeMeta::Dynamic
2578        ));
2579
2580        proptest!(proptest_cfg(), |(value: Result<u64, String>)| {
2581            let wincode_serialized = serialize(&value).unwrap();
2582            let bincode_serialized = bincode::serialize(&value).unwrap();
2583            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
2584
2585            let wincode_deserialized: Result<u64, String> = deserialize(&wincode_serialized).unwrap();
2586            let bincode_deserialized: Result<u64, String> = bincode::deserialize(&bincode_serialized).unwrap();
2587            prop_assert_eq!(&value, &wincode_deserialized);
2588            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
2589        });
2590    }
2591
2592    #[test]
2593    fn test_result_type_meta_different_sizes() {
2594        // Result<u64, u32> should be TypeMeta::Dynamic because T and E have different sizes
2595        assert!(matches!(
2596            <Result<u64, u32> as SchemaRead>::TYPE_META,
2597            TypeMeta::Dynamic
2598        ));
2599
2600        proptest!(proptest_cfg(), |(value: Result<u64, u32>)| {
2601            let wincode_serialized = serialize(&value).unwrap();
2602            let bincode_serialized = bincode::serialize(&value).unwrap();
2603            prop_assert_eq!(&wincode_serialized, &bincode_serialized);
2604
2605            let wincode_deserialized: Result<u64, u32> = deserialize(&wincode_serialized).unwrap();
2606            let bincode_deserialized: Result<u64, u32> = bincode::deserialize(&bincode_serialized).unwrap();
2607            prop_assert_eq!(&value, &wincode_deserialized);
2608            prop_assert_eq!(wincode_deserialized, bincode_deserialized);
2609        });
2610    }
2611
2612    /// A buffer containing a single instance of type `T`,
2613    /// aligned for `T`.
2614    ///
2615    /// Implements [`Deref`] and [`DerefMut`] for `[u8]` such that it
2616    /// acts like a typical byte buffer, but aligned for `T`.
2617    struct BufAligned<T> {
2618        buf: Box<[T]>,
2619    }
2620
2621    impl<T> Deref for BufAligned<T>
2622    where
2623        T: ZeroCopy,
2624    {
2625        type Target = [u8];
2626
2627        fn deref(&self) -> &Self::Target {
2628            unsafe {
2629                core::slice::from_raw_parts(
2630                    self.buf.as_ptr() as *const u8,
2631                    self.buf.len() * size_of::<T>(),
2632                )
2633            }
2634        }
2635    }
2636
2637    impl<T> DerefMut for BufAligned<T>
2638    where
2639        T: ZeroCopy,
2640    {
2641        fn deref_mut(&mut self) -> &mut Self::Target {
2642            unsafe {
2643                core::slice::from_raw_parts_mut(
2644                    self.buf.as_mut_ptr() as *mut u8,
2645                    self.buf.len() * size_of::<T>(),
2646                )
2647            }
2648        }
2649    }
2650
2651    /// Serialize a single instance of type `T` into a buffer aligned for `T`.
2652    fn serialize_aligned<T>(src: &T) -> WriteResult<BufAligned<T>>
2653    where
2654        T: SchemaWrite<Src = T> + ZeroCopy,
2655    {
2656        assert_eq!(T::size_of(src)?, size_of::<T>());
2657        let mut b: Box<[MaybeUninit<T>]> = Box::new_uninit_slice(1);
2658        let mut buf =
2659            unsafe { core::slice::from_raw_parts_mut(b.as_mut_ptr() as *mut u8, size_of::<T>()) };
2660        crate::serialize_into(&mut buf, src)?;
2661        Ok(BufAligned {
2662            buf: unsafe { b.assume_init() },
2663        })
2664    }
2665
2666    #[test]
2667    fn test_zero_copy_mut_roundrip() {
2668        proptest!(proptest_cfg(), |(data: StructZeroCopy, data_rand: StructZeroCopy)| {
2669            let mut serialized = serialize_aligned(&data).unwrap();
2670            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
2671            prop_assert_eq!(deserialized, data);
2672
2673
2674            // Mutate the serialized data in place
2675            {
2676                let ref_mut = StructZeroCopy::from_bytes_mut(&mut serialized).unwrap();
2677                *ref_mut = data_rand;
2678            }
2679            // Deserialize again on the same serialized data to
2680            // verify the changes were persisted
2681            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
2682            prop_assert_eq!(deserialized, data_rand);
2683        });
2684    }
2685
2686    #[test]
2687    fn test_deserialize_mut_roundrip() {
2688        proptest!(proptest_cfg(), |(data: StructZeroCopy, data_rand: StructZeroCopy)| {
2689            let mut serialized = serialize_aligned(&data).unwrap();
2690            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
2691            prop_assert_eq!(deserialized, data);
2692
2693
2694            // Mutate the serialized data in place
2695            {
2696                let ref_mut: &mut StructZeroCopy = deserialize_mut(&mut serialized).unwrap();
2697                *ref_mut = data_rand;
2698            }
2699            // Deserialize again on the same serialized data to
2700            // verify the changes were persisted
2701            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
2702            prop_assert_eq!(deserialized, data_rand);
2703        });
2704    }
2705
2706    #[test]
2707    fn test_zero_copy_deserialize_ref() {
2708        proptest!(proptest_cfg(), |(data: StructZeroCopy)| {
2709            let serialized = serialize_aligned(&data).unwrap();
2710            let deserialized: StructZeroCopy = deserialize(&serialized).unwrap();
2711            prop_assert_eq!(deserialized, data);
2712
2713            let ref_data = StructZeroCopy::from_bytes(&serialized).unwrap();
2714            prop_assert_eq!(ref_data, &data);
2715        });
2716    }
2717
2718    #[test]
2719    #[cfg(feature = "bytes")]
2720    fn test_bytes_roundtrip() {
2721        proptest!(proptest_cfg(), |(data in proptest::collection::vec(any::<u8>(), 0..1000).prop_map(bytes::Bytes::from))| {
2722            let serialized = serialize(&data).unwrap();
2723            let deserialized: bytes::Bytes = deserialize(&serialized).unwrap();
2724            prop_assert_eq!(data, deserialized);
2725        });
2726    }
2727
2728    #[test]
2729    #[cfg(feature = "bytes")]
2730    fn test_bytes_mut_roundtrip() {
2731        proptest!(proptest_cfg(), |(data in proptest::collection::vec(any::<u8>(), 0..1000).prop_map(|v| bytes::BytesMut::from(v.as_slice())))| {
2732            let serialized = serialize(&data).unwrap();
2733            let deserialized: bytes::BytesMut = deserialize(&serialized).unwrap();
2734            prop_assert_eq!(data, deserialized);
2735        });
2736    }
2737}