Skip to main content

wincode/schema/
impls.rs

1//! Blanket implementations for std types.
2//!
3//! Because the blanket implementations must be entirely general (e.g., we
4//! need to support `Vec<T>` for any `T`), we can't make any assumptions about
5//! the "Plain Old Data" nature of `T`, so all sequences will treat constituent
6//! elements of `T` as opaque. Of course users can use `std::vec::Vec<Pod<T>>`,
7//! which will certainly speed things up for POD elements of sequences, but
8//! the optimization will only be _per_ element.
9//!
10//! Additionally, we have to assume [`BincodeLen`] for all sequences, because
11//! there is no way to specify a different length encoding without one of the
12//! [`containers`].
13#[cfg(feature = "std")]
14use std::{
15    collections::{HashMap, HashSet},
16    hash::Hash,
17};
18use {
19    crate::{
20        containers::SliceDropGuard,
21        error::{
22            invalid_bool_encoding, invalid_char_lead, invalid_tag_encoding, invalid_utf8_encoding,
23            pointer_sized_decode_error, read_length_encoding_overflow, unaligned_pointer_read,
24            ReadResult, WriteResult,
25        },
26        io::{Reader, Writer},
27        len::{BincodeLen, SeqLen},
28        schema::{size_of_elem_slice, write_elem_slice, SchemaRead, SchemaWrite, ZeroCopy},
29        TypeMeta,
30    },
31    core::{
32        marker::PhantomData,
33        mem::{self, transmute, MaybeUninit},
34    },
35};
36#[cfg(feature = "alloc")]
37use {
38    crate::{
39        containers::{self},
40        error::WriteError,
41        schema::{size_of_elem_iter, write_elem_iter},
42    },
43    alloc::{
44        boxed::Box,
45        collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
46        rc::Rc,
47        string::String,
48        sync::Arc,
49        vec::Vec,
50    },
51};
52
53macro_rules! impl_int {
54    ($type:ty, zero_copy: $zero_copy:expr) => {
55        impl SchemaWrite for $type {
56            type Src = $type;
57
58            const TYPE_META: TypeMeta = TypeMeta::Static {
59                size: size_of::<$type>(),
60                #[cfg(target_endian = "little")]
61                zero_copy: true,
62                #[cfg(not(target_endian = "little"))]
63                zero_copy: $zero_copy,
64            };
65
66            #[inline(always)]
67            fn size_of(_src: &Self::Src) -> WriteResult<usize> {
68                Ok(size_of::<$type>())
69            }
70
71            #[inline(always)]
72            fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
73                Ok(writer.write(&src.to_le_bytes())?)
74            }
75        }
76
77        impl<'de> SchemaRead<'de> for $type {
78            type Dst = $type;
79
80            const TYPE_META: TypeMeta = TypeMeta::Static {
81                size: size_of::<$type>(),
82                #[cfg(target_endian = "little")]
83                zero_copy: true,
84                #[cfg(not(target_endian = "little"))]
85                zero_copy: $zero_copy,
86            };
87
88            #[inline(always)]
89            fn read(
90                reader: &mut impl Reader<'de>,
91                dst: &mut MaybeUninit<Self::Dst>,
92            ) -> ReadResult<()> {
93                // SAFETY: integer is plain ol' data.
94                let bytes = reader.fill_array::<{ size_of::<$type>() }>()?;
95                // bincode defaults to little endian encoding.
96                dst.write(<$type>::from_le_bytes(*bytes));
97                unsafe { reader.consume_unchecked(size_of::<$type>()) };
98
99                Ok(())
100            }
101        }
102    };
103
104    ($type:ty as $cast:ty) => {
105        impl SchemaWrite for $type {
106            type Src = $type;
107
108            const TYPE_META: TypeMeta = TypeMeta::Static {
109                size: size_of::<$cast>(),
110                zero_copy: false,
111            };
112
113            #[inline]
114            fn size_of(_src: &Self::Src) -> WriteResult<usize> {
115                Ok(size_of::<$cast>())
116            }
117
118            #[inline]
119            fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
120                let src = *src as $cast;
121                // bincode defaults to little endian encoding.
122                // noop on LE machines.
123                Ok(writer.write(&src.to_le_bytes())?)
124            }
125        }
126
127        impl<'de> SchemaRead<'de> for $type {
128            type Dst = $type;
129
130            const TYPE_META: TypeMeta = TypeMeta::Static {
131                size: size_of::<$cast>(),
132                zero_copy: false,
133            };
134
135            #[inline]
136            fn read(
137                reader: &mut impl Reader<'de>,
138                dst: &mut MaybeUninit<Self::Dst>,
139            ) -> ReadResult<()> {
140                let casted = <$cast>::get(reader)?;
141                let val = casted
142                    .try_into()
143                    .map_err(|_| pointer_sized_decode_error())?;
144
145                dst.write(val);
146
147                Ok(())
148            }
149        }
150    };
151}
152
153// SAFETY:
154// - u8 is a canonical zero-copy type: no endianness, no layout, no validation.
155unsafe impl ZeroCopy for u8 {}
156
157// SAFETY:
158// - i8 is similarly a canonical zero-copy type: no endianness, no layout, no validation.
159unsafe impl ZeroCopy for i8 {}
160
161macro_rules! impl_numeric_zero_copy {
162    ($($ty:ty),+ $(,)?) => {
163        $(
164            unsafe impl ZeroCopy for $ty {}
165        )+
166    };
167}
168
169// SAFETY: Primitive numeric types with fixed size. Only valid on little endian
170// platforms because Bincode specifies little endian integer encoding.
171#[cfg(target_endian = "little")]
172impl_numeric_zero_copy!(u16, i16, u32, i32, u64, i64, u128, i128, f32, f64);
173
174impl_int!(u8, zero_copy: true);
175impl_int!(i8, zero_copy: true);
176impl_int!(u16, zero_copy: false);
177impl_int!(i16, zero_copy: false);
178impl_int!(u32, zero_copy: false);
179impl_int!(i32, zero_copy: false);
180impl_int!(u64, zero_copy: false);
181impl_int!(i64, zero_copy: false);
182impl_int!(u128, zero_copy: false);
183impl_int!(i128, zero_copy: false);
184impl_int!(f32, zero_copy: false);
185impl_int!(f64, zero_copy: false);
186impl_int!(usize as u64);
187impl_int!(isize as i64);
188
189impl SchemaWrite for bool {
190    type Src = bool;
191
192    const TYPE_META: TypeMeta = TypeMeta::Static {
193        size: size_of::<bool>(),
194        zero_copy: false,
195    };
196
197    #[inline]
198    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
199        Ok(size_of::<u8>())
200    }
201
202    #[inline]
203    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
204        unsafe { Ok(writer.write_t(&(*src as u8))?) }
205    }
206}
207
208impl<'de> SchemaRead<'de> for bool {
209    type Dst = bool;
210
211    const TYPE_META: TypeMeta = TypeMeta::Static {
212        size: size_of::<bool>(),
213        zero_copy: false,
214    };
215
216    #[inline]
217    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
218        // SAFETY: u8 is plain ol' data.
219        let byte = u8::get(reader)?;
220        match byte {
221            0 => {
222                dst.write(false);
223            }
224            1 => {
225                dst.write(true);
226            }
227            _ => return Err(invalid_bool_encoding(byte)),
228        }
229        Ok(())
230    }
231}
232
233impl SchemaWrite for char {
234    type Src = char;
235
236    #[inline]
237    fn size_of(src: &Self::Src) -> WriteResult<usize> {
238        let mut buf = [0; 4];
239        let str = src.encode_utf8(&mut buf);
240        Ok(str.len())
241    }
242
243    #[inline]
244    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
245        let mut buf = [0; 4];
246        let str = src.encode_utf8(&mut buf);
247        writer.write(str.as_bytes())?;
248        Ok(())
249    }
250}
251
252impl<'de> SchemaRead<'de> for char {
253    type Dst = char;
254
255    #[inline]
256    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
257        let b0 = *reader.peek()?;
258
259        let len = match b0 {
260            0x00..=0x7F => 1,
261            0xC2..=0xDF => 2,
262            0xE0..=0xEF => 3,
263            0xF0..=0xF4 => 4,
264            _ => return Err(invalid_char_lead(b0)),
265        };
266
267        if len == 1 {
268            unsafe { reader.consume_unchecked(1) };
269            dst.write(b0 as char);
270            return Ok(());
271        }
272
273        let buf = reader.fill_exact(len)?;
274        // TODO: Could implement a manual decoder that avoids UTF-8 validate + chars()
275        // and instead performs the UTF-8 validity checks and produces a `char` directly.
276        // Some quick micro-benchmarking revealed a roughly 2x speedup is possible,
277        // but this is on the order of a 1-2ns/byte delta.
278        let str = core::str::from_utf8(buf).map_err(invalid_utf8_encoding)?;
279        let c = str.chars().next().unwrap();
280        unsafe { reader.consume_unchecked(len) };
281        dst.write(c);
282        Ok(())
283    }
284}
285
286impl<T> SchemaWrite for PhantomData<T> {
287    type Src = PhantomData<T>;
288
289    const TYPE_META: TypeMeta = TypeMeta::Static {
290        size: 0,
291        zero_copy: true,
292    };
293
294    #[inline]
295    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
296        Ok(0)
297    }
298
299    #[inline]
300    fn write(_writer: &mut impl Writer, _src: &Self::Src) -> WriteResult<()> {
301        Ok(())
302    }
303}
304
305impl<'de, T> SchemaRead<'de> for PhantomData<T> {
306    type Dst = PhantomData<T>;
307
308    const TYPE_META: TypeMeta = TypeMeta::Static {
309        size: 0,
310        zero_copy: true,
311    };
312
313    #[inline]
314    fn read(_reader: &mut impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
315        Ok(())
316    }
317}
318
319impl SchemaWrite for () {
320    type Src = ();
321
322    const TYPE_META: TypeMeta = TypeMeta::Static {
323        size: 0,
324        zero_copy: true,
325    };
326
327    #[inline]
328    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
329        Ok(0)
330    }
331
332    #[inline]
333    fn write(_writer: &mut impl Writer, _src: &Self::Src) -> WriteResult<()> {
334        Ok(())
335    }
336}
337
338impl<'de> SchemaRead<'de> for () {
339    type Dst = ();
340
341    const TYPE_META: TypeMeta = TypeMeta::Static {
342        size: 0,
343        zero_copy: true,
344    };
345
346    #[inline]
347    fn read(_reader: &mut impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
348        Ok(())
349    }
350}
351
352#[cfg(feature = "alloc")]
353impl<T> SchemaWrite for Vec<T>
354where
355    T: SchemaWrite,
356    T::Src: Sized,
357{
358    type Src = Vec<T::Src>;
359
360    #[inline]
361    fn size_of(value: &Self::Src) -> WriteResult<usize> {
362        <containers::Vec<T, BincodeLen<{ 1 << 27 }>>>::size_of(value)
363    }
364
365    #[inline]
366    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
367        <containers::Vec<T, BincodeLen<{ 1 << 27 }>>>::write(writer, value)
368    }
369}
370
371#[cfg(feature = "alloc")]
372impl<'de, T> SchemaRead<'de> for Vec<T>
373where
374    T: SchemaRead<'de>,
375{
376    type Dst = Vec<T::Dst>;
377
378    #[inline]
379    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
380        <containers::Vec<T, BincodeLen<{ 1 << 27 }>>>::read(reader, dst)
381    }
382}
383
384#[cfg(feature = "alloc")]
385impl<T> SchemaWrite for VecDeque<T>
386where
387    T: SchemaWrite,
388    T::Src: Sized,
389{
390    type Src = VecDeque<T::Src>;
391
392    #[inline]
393    fn size_of(value: &Self::Src) -> WriteResult<usize> {
394        <containers::VecDeque<T, BincodeLen>>::size_of(value)
395    }
396
397    #[inline]
398    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
399        <containers::VecDeque<T, BincodeLen>>::write(writer, value)
400    }
401}
402
403#[cfg(feature = "alloc")]
404impl<'de, T> SchemaRead<'de> for VecDeque<T>
405where
406    T: SchemaRead<'de>,
407{
408    type Dst = VecDeque<T::Dst>;
409
410    #[inline]
411    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
412        <containers::VecDeque<T, BincodeLen>>::read(reader, dst)
413    }
414}
415
416impl<T> SchemaWrite for [T]
417where
418    T: SchemaWrite,
419    T::Src: Sized,
420{
421    type Src = [T::Src];
422
423    #[inline]
424    fn size_of(value: &Self::Src) -> WriteResult<usize> {
425        size_of_elem_slice::<T, BincodeLen>(value)
426    }
427
428    #[inline]
429    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
430        write_elem_slice::<T, BincodeLen>(writer, value)
431    }
432}
433
434// SAFETY:
435// - [T; N] where T: ZeroCopy is trivially zero-copy. The length is constant,
436//   so there is no length encoding.
437unsafe impl<const N: usize, T> ZeroCopy for [T; N] where T: ZeroCopy {}
438
439impl<'de, T, const N: usize> SchemaRead<'de> for [T; N]
440where
441    T: SchemaRead<'de>,
442{
443    type Dst = [T::Dst; N];
444
445    const TYPE_META: TypeMeta = const {
446        match T::TYPE_META {
447            TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
448                size: N * size,
449                zero_copy,
450            },
451            TypeMeta::Dynamic => TypeMeta::Dynamic,
452        }
453    };
454
455    #[inline]
456    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
457        if let TypeMeta::Static {
458            zero_copy: true, ..
459        } = T::TYPE_META
460        {
461            // SAFETY: `T::Dst` is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
462            unsafe { reader.copy_into_t(dst)? };
463            return Ok(());
464        }
465
466        // SAFETY: MaybeUninit<[T::Dst; N]> trivially converts to [MaybeUninit<T::Dst>; N].
467        let dst =
468            unsafe { transmute::<&mut MaybeUninit<Self::Dst>, &mut [MaybeUninit<T::Dst>; N]>(dst) };
469        let base = dst.as_mut_ptr();
470        let mut guard = SliceDropGuard::<T::Dst>::new(base);
471        if let TypeMeta::Static { size, .. } = Self::TYPE_META {
472            // SAFETY: `Self::TYPE_META` specifies a static size, which is `N * static_size_of(T)`.
473            // `N` reads of `T` will consume `size` bytes, fully consuming the trusted window.
474            let reader = &mut unsafe { reader.as_trusted_for(size) }?;
475            for i in 0..N {
476                let slot = unsafe { &mut *base.add(i) };
477                T::read(reader, slot)?;
478                guard.inc_len();
479            }
480        } else {
481            for i in 0..N {
482                let slot = unsafe { &mut *base.add(i) };
483                T::read(reader, slot)?;
484                guard.inc_len();
485            }
486        }
487        mem::forget(guard);
488        Ok(())
489    }
490}
491
492impl<T, const N: usize> SchemaWrite for [T; N]
493where
494    T: SchemaWrite,
495    T::Src: Sized,
496{
497    type Src = [T::Src; N];
498
499    const TYPE_META: TypeMeta = const {
500        match T::TYPE_META {
501            TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
502                size: N * size,
503                zero_copy,
504            },
505            TypeMeta::Dynamic => TypeMeta::Dynamic,
506        }
507    };
508
509    #[inline]
510    #[allow(clippy::arithmetic_side_effects)]
511    fn size_of(value: &Self::Src) -> WriteResult<usize> {
512        if let TypeMeta::Static { size, .. } = Self::TYPE_META {
513            return Ok(size);
514        }
515        // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
516        value
517            .iter()
518            .map(T::size_of)
519            .try_fold(0usize, |acc, x| x.map(|x| acc + x))
520    }
521
522    #[inline]
523    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
524        match Self::TYPE_META {
525            TypeMeta::Static {
526                zero_copy: true, ..
527            } => {
528                // SAFETY: `T::Src` is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
529                unsafe { writer.write_slice_t(value)? };
530            }
531            TypeMeta::Static {
532                size,
533                zero_copy: false,
534            } => {
535                // SAFETY: `Self::TYPE_META` specifies a static size, which is `N * static_size_of(T)`.
536                // `N` writes of `T` will write `size` bytes, fully initializing the trusted window.
537                let writer = &mut unsafe { writer.as_trusted_for(size) }?;
538                for item in value {
539                    T::write(writer, item)?;
540                }
541                writer.finish()?;
542            }
543            TypeMeta::Dynamic => {
544                for item in value {
545                    T::write(writer, item)?;
546                }
547            }
548        }
549
550        Ok(())
551    }
552}
553
554impl<'de, T> SchemaRead<'de> for Option<T>
555where
556    T: SchemaRead<'de>,
557{
558    type Dst = Option<T::Dst>;
559
560    #[inline]
561    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
562        let variant = u8::get(reader)?;
563        match variant {
564            0 => dst.write(Option::None),
565            1 => dst.write(Option::Some(T::get(reader)?)),
566            _ => return Err(invalid_tag_encoding(variant as usize)),
567        };
568
569        Ok(())
570    }
571}
572
573impl<T> SchemaWrite for Option<T>
574where
575    T: SchemaWrite,
576    T::Src: Sized,
577{
578    type Src = Option<T::Src>;
579
580    #[inline]
581    #[allow(clippy::arithmetic_side_effects)]
582    fn size_of(src: &Self::Src) -> WriteResult<usize> {
583        match src {
584            // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
585            Option::Some(value) => Ok(1 + T::size_of(value)?),
586            Option::None => Ok(1),
587        }
588    }
589
590    #[inline]
591    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
592        match value {
593            Option::Some(value) => {
594                u8::write(writer, &1)?;
595                T::write(writer, value)
596            }
597            Option::None => u8::write(writer, &0),
598        }
599    }
600}
601
602impl<'de, T, E> SchemaRead<'de> for Result<T, E>
603where
604    T: SchemaRead<'de>,
605    E: SchemaRead<'de>,
606{
607    type Dst = Result<T::Dst, E::Dst>;
608
609    const TYPE_META: TypeMeta = match (T::TYPE_META, E::TYPE_META) {
610        (TypeMeta::Static { size: t_size, .. }, TypeMeta::Static { size: e_size, .. })
611            if t_size == e_size =>
612        {
613            TypeMeta::Static {
614                size: size_of::<u32>() + t_size,
615                zero_copy: false,
616            }
617        }
618        _ => TypeMeta::Dynamic,
619    };
620
621    #[inline]
622    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
623        let variant = u32::get(reader)?;
624        match variant {
625            0 => dst.write(Result::Ok(T::get(reader)?)),
626            1 => dst.write(Result::Err(E::get(reader)?)),
627            _ => return Err(invalid_tag_encoding(variant as usize)),
628        };
629
630        Ok(())
631    }
632}
633
634impl<T, E> SchemaWrite for Result<T, E>
635where
636    T: SchemaWrite,
637    E: SchemaWrite,
638    T::Src: Sized,
639    E::Src: Sized,
640{
641    type Src = Result<T::Src, E::Src>;
642
643    const TYPE_META: TypeMeta = match (T::TYPE_META, E::TYPE_META) {
644        (TypeMeta::Static { size: t_size, .. }, TypeMeta::Static { size: e_size, .. })
645            if t_size == e_size =>
646        {
647            TypeMeta::Static {
648                size: size_of::<u32>() + t_size,
649                zero_copy: false,
650            }
651        }
652        _ => TypeMeta::Dynamic,
653    };
654
655    #[inline]
656    #[allow(clippy::arithmetic_side_effects)]
657    fn size_of(src: &Self::Src) -> WriteResult<usize> {
658        match src {
659            // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
660            Result::Ok(value) => Ok(size_of::<u32>() + T::size_of(value)?),
661            Result::Err(error) => Ok(size_of::<u32>() + E::size_of(error)?),
662        }
663    }
664
665    #[inline]
666    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
667        match value {
668            Result::Ok(value) => {
669                u32::write(writer, &0)?;
670                T::write(writer, value)
671            }
672            Result::Err(error) => {
673                u32::write(writer, &1)?;
674                E::write(writer, error)
675            }
676        }
677    }
678}
679
680impl<'a, T> SchemaWrite for &'a T
681where
682    T: SchemaWrite,
683    T: ?Sized,
684{
685    type Src = &'a T::Src;
686
687    const TYPE_META: TypeMeta = T::TYPE_META;
688
689    #[inline]
690    fn size_of(src: &Self::Src) -> WriteResult<usize> {
691        T::size_of(*src)
692    }
693
694    #[inline]
695    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
696        T::write(writer, *value)
697    }
698}
699
700macro_rules! impl_heap_container {
701    ($container:ident) => {
702        #[cfg(feature = "alloc")]
703        impl<T> SchemaWrite for $container<T>
704        where
705            T: SchemaWrite,
706        {
707            type Src = $container<T::Src>;
708
709            const TYPE_META: TypeMeta = const {
710                match T::TYPE_META {
711                    TypeMeta::Static { size, .. } => TypeMeta::Static {
712                        size,
713                        zero_copy: false,
714                    },
715                    TypeMeta::Dynamic => TypeMeta::Dynamic,
716                }
717            };
718
719            #[inline]
720            fn size_of(src: &Self::Src) -> WriteResult<usize> {
721                T::size_of(src)
722            }
723
724            #[inline]
725            fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
726                T::write(writer, value)
727            }
728        }
729
730        #[cfg(feature = "alloc")]
731        impl<'de, T> SchemaRead<'de> for $container<T>
732        where
733            T: SchemaRead<'de>,
734        {
735            type Dst = $container<T::Dst>;
736
737            const TYPE_META: TypeMeta = const {
738                match T::TYPE_META {
739                    TypeMeta::Static { size, .. } => TypeMeta::Static {
740                        size,
741                        zero_copy: false,
742                    },
743                    TypeMeta::Dynamic => TypeMeta::Dynamic,
744                }
745            };
746
747            #[inline]
748            fn read(
749                reader: &mut impl Reader<'de>,
750                dst: &mut MaybeUninit<Self::Dst>,
751            ) -> ReadResult<()> {
752                struct DropGuard<T>(*mut MaybeUninit<T>);
753                impl<T> Drop for DropGuard<T> {
754                    #[inline]
755                    fn drop(&mut self) {
756                        drop(unsafe { $container::from_raw(self.0) });
757                    }
758                }
759
760                let mem = $container::<T::Dst>::new_uninit();
761                let ptr = $container::into_raw(mem) as *mut _;
762                let guard: DropGuard<T::Dst> = DropGuard(ptr);
763                T::read(reader, unsafe { &mut *ptr })?;
764
765                mem::forget(guard);
766
767                unsafe {
768                    // SAFETY: `T::read` must properly initialize the `T::Dst`.
769                    dst.write($container::from_raw(ptr).assume_init());
770                }
771                Ok(())
772            }
773        }
774    };
775}
776
777impl_heap_container!(Box);
778impl_heap_container!(Rc);
779impl_heap_container!(Arc);
780
781#[cfg(feature = "alloc")]
782impl<T> SchemaWrite for Box<[T]>
783where
784    T: SchemaWrite,
785    T::Src: Sized,
786{
787    type Src = Box<[T::Src]>;
788
789    #[inline]
790    fn size_of(src: &Self::Src) -> WriteResult<usize> {
791        <containers::Box<[T], BincodeLen>>::size_of(src)
792    }
793
794    #[inline]
795    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
796        <containers::Box<[T], BincodeLen>>::write(writer, value)
797    }
798}
799
800#[cfg(feature = "alloc")]
801impl<T> SchemaWrite for Rc<[T]>
802where
803    T: SchemaWrite,
804    T::Src: Sized,
805{
806    type Src = Rc<[T::Src]>;
807
808    #[inline]
809    fn size_of(src: &Self::Src) -> WriteResult<usize> {
810        <containers::Rc<[T], BincodeLen>>::size_of(src)
811    }
812
813    #[inline]
814    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
815        <containers::Rc<[T], BincodeLen>>::write(writer, value)
816    }
817}
818
819#[cfg(feature = "alloc")]
820impl<T> SchemaWrite for Arc<[T]>
821where
822    T: SchemaWrite,
823    T::Src: Sized,
824{
825    type Src = Arc<[T::Src]>;
826
827    #[inline]
828    fn size_of(src: &Self::Src) -> WriteResult<usize> {
829        <containers::Arc<[T], BincodeLen>>::size_of(src)
830    }
831
832    #[inline]
833    fn write(writer: &mut impl Writer, value: &Self::Src) -> WriteResult<()> {
834        <containers::Arc<[T], BincodeLen>>::write(writer, value)
835    }
836}
837
838#[cfg(feature = "alloc")]
839impl<'de, T> SchemaRead<'de> for Box<[T]>
840where
841    T: SchemaRead<'de>,
842{
843    type Dst = Box<[T::Dst]>;
844
845    #[inline]
846    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
847        <containers::Box<[T], BincodeLen>>::read(reader, dst)
848    }
849}
850
851#[cfg(feature = "alloc")]
852impl<'de, T> SchemaRead<'de> for Rc<[T]>
853where
854    T: SchemaRead<'de>,
855{
856    type Dst = Rc<[T::Dst]>;
857
858    #[inline]
859    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
860        <containers::Rc<[T], BincodeLen>>::read(reader, dst)
861    }
862}
863
864#[cfg(feature = "alloc")]
865impl<'de, T> SchemaRead<'de> for Arc<[T]>
866where
867    T: SchemaRead<'de>,
868{
869    type Dst = Arc<[T::Dst]>;
870
871    #[inline]
872    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
873        <containers::Arc<[T], BincodeLen>>::read(reader, dst)
874    }
875}
876
877impl SchemaWrite for str {
878    type Src = str;
879
880    #[inline]
881    #[allow(clippy::arithmetic_side_effects)]
882    fn size_of(src: &Self::Src) -> WriteResult<usize> {
883        // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
884        Ok(<BincodeLen>::write_bytes_needed(src.len())? + src.len())
885    }
886
887    #[inline]
888    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
889        <BincodeLen>::write(writer, src.len())?;
890        writer.write(src.as_bytes())?;
891        Ok(())
892    }
893}
894
895#[cfg(feature = "alloc")]
896impl SchemaWrite for String {
897    type Src = String;
898
899    #[inline]
900    fn size_of(src: &Self::Src) -> WriteResult<usize> {
901        <str>::size_of(src)
902    }
903
904    #[inline]
905    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
906        <str>::write(writer, src)
907    }
908}
909
910impl<'de> SchemaRead<'de> for &'de str {
911    type Dst = &'de str;
912
913    #[inline]
914    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
915        let len = <BincodeLen>::read::<u8>(reader)?;
916        let bytes = reader.borrow_exact(len)?;
917        match core::str::from_utf8(bytes) {
918            Ok(s) => {
919                dst.write(s);
920                Ok(())
921            }
922            Err(e) => Err(invalid_utf8_encoding(e)),
923        }
924    }
925}
926
927#[cfg(feature = "alloc")]
928impl<'de> SchemaRead<'de> for String {
929    type Dst = String;
930
931    #[inline]
932    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
933        let len = <BincodeLen>::read::<u8>(reader)?;
934        let bytes = reader.fill_exact(len)?.to_vec();
935        unsafe { reader.consume_unchecked(len) };
936        match String::from_utf8(bytes) {
937            Ok(s) => {
938                dst.write(s);
939                Ok(())
940            }
941            Err(e) => Err(invalid_utf8_encoding(e.utf8_error())),
942        }
943    }
944}
945
946#[cfg(feature = "bytes")]
947impl SchemaWrite for bytes::Bytes {
948    type Src = bytes::Bytes;
949
950    #[inline]
951    fn size_of(src: &Self::Src) -> WriteResult<usize> {
952        <containers::Bytes<BincodeLen>>::size_of(src)
953    }
954
955    #[inline]
956    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
957        <containers::Bytes<BincodeLen>>::write(writer, src)
958    }
959}
960
961#[cfg(feature = "bytes")]
962impl<'de> SchemaRead<'de> for bytes::Bytes {
963    type Dst = bytes::Bytes;
964
965    #[inline]
966    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
967        <containers::Bytes<BincodeLen>>::read(reader, dst)
968    }
969}
970
971#[cfg(feature = "bytes")]
972impl SchemaWrite for bytes::BytesMut {
973    type Src = bytes::BytesMut;
974
975    #[inline]
976    fn size_of(src: &Self::Src) -> WriteResult<usize> {
977        <containers::BytesMut<BincodeLen>>::size_of(src)
978    }
979
980    #[inline]
981    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
982        <containers::BytesMut<BincodeLen>>::write(writer, src)
983    }
984}
985
986#[cfg(feature = "bytes")]
987impl<'de> SchemaRead<'de> for bytes::BytesMut {
988    type Dst = bytes::BytesMut;
989
990    #[inline]
991    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
992        <containers::BytesMut<BincodeLen>>::read(reader, dst)
993    }
994}
995
996/// Implement `SchemaWrite` and `SchemaRead` for types that may be iterated over sequentially.
997///
998/// Generally this should only be used on types for which we cannot provide an optimized implementation,
999/// and where the most optimal implementation is simply iterating over the type to write or collecting
1000/// to read -- typically non-contiguous sequences like `HashMap` or `BTreeMap` (or their set variants).
1001macro_rules! impl_seq {
1002    ($feature: literal, $target: ident<$key: ident : $($constraint:path)|*, $value: ident>, $with_capacity: expr) => {
1003        #[cfg(feature = $feature)]
1004        impl<$key, $value> SchemaWrite for $target<$key, $value>
1005        where
1006            $key: SchemaWrite,
1007            $key::Src: Sized,
1008            $value: SchemaWrite,
1009            $value::Src: Sized,
1010        {
1011            type Src = $target<$key::Src, $value::Src>;
1012
1013            #[inline]
1014            #[allow(clippy::arithmetic_side_effects)]
1015            fn size_of(src: &Self::Src) -> WriteResult<usize> {
1016                if let (TypeMeta::Static { size: key_size, .. }, TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
1017                    return Ok(<BincodeLen>::write_bytes_needed(src.len())? + (key_size + value_size) * src.len());
1018                }
1019                Ok(<BincodeLen>::write_bytes_needed(src.len())? +
1020                    src
1021                        .iter()
1022                        .try_fold(
1023                            0usize,
1024                            |acc, (k, v)|
1025                            Ok::<_, WriteError>(
1026                                acc
1027                                + $key::size_of(k)?
1028                                + $value::size_of(v)?
1029                            )
1030                    )?
1031                )
1032            }
1033
1034            #[inline]
1035            fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
1036                if let (TypeMeta::Static { size: key_size, .. }, TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
1037                    let len = src.len();
1038                    #[allow(clippy::arithmetic_side_effects)]
1039                    let needed = <BincodeLen>::write_bytes_needed(len)? + (key_size + value_size) * len;
1040                    // SAFETY: `$key::TYPE_META` and `$value::TYPE_META` specify static sizes, so `len` writes of `($key::Src, $value::Src)`
1041                    // and `<BincodeLen>::write` will write `needed` bytes, fully initializing the trusted window.
1042                    let writer = &mut unsafe { writer.as_trusted_for(needed) }?;
1043                    <BincodeLen>::write(writer, len)?;
1044                    for (k, v) in src.iter() {
1045                        $key::write(writer, k)?;
1046                        $value::write(writer, v)?;
1047                    }
1048                    writer.finish()?;
1049                    return Ok(());
1050                }
1051                <BincodeLen>::write(writer, src.len())?;
1052                for (k, v) in src.iter() {
1053                    $key::write(writer, k)?;
1054                    $value::write(writer, v)?;
1055                }
1056                Ok(())
1057            }
1058        }
1059
1060        #[cfg(feature = $feature)]
1061        impl<'de, $key, $value> SchemaRead<'de> for $target<$key, $value>
1062        where
1063            $key: SchemaRead<'de>,
1064            $value: SchemaRead<'de>
1065            $(,$key::Dst: $constraint+)*,
1066        {
1067            type Dst = $target<$key::Dst, $value::Dst>;
1068
1069            #[inline]
1070            fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1071                let len = <BincodeLen>::read::<($key::Dst, $value::Dst)>(reader)?;
1072
1073                let map = if let (TypeMeta::Static { size: key_size, .. }, TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
1074                    #[allow(clippy::arithmetic_side_effects)]
1075                    // SAFETY: `$key::TYPE_META` and `$value::TYPE_META` specify static sizes, so `len` reads of `($key::Dst, $value::Dst)`
1076                    // will consume `(key_size + value_size) * len` bytes, fully consuming the trusted window.
1077                    let reader = &mut unsafe { reader.as_trusted_for((key_size + value_size) * len) }?;
1078                    let mut map = $with_capacity(len);
1079                    for _ in 0..len {
1080                        let k = $key::get(reader)?;
1081                        let v = $value::get(reader)?;
1082                        map.insert(k, v);
1083                    }
1084                    map
1085                } else {
1086                    let mut map = $with_capacity(len);
1087                    for _ in 0..len {
1088                        let k = $key::get(reader)?;
1089                        let v = $value::get(reader)?;
1090                        map.insert(k, v);
1091                    }
1092                    map
1093                };
1094
1095                dst.write(map);
1096                Ok(())
1097            }
1098        }
1099    };
1100
1101    ($feature: literal, $target: ident <$key: ident : $($constraint:path)|*>, $with_capacity: expr, $insert: ident) => {
1102        #[cfg(feature = $feature)]
1103        impl<$key: SchemaWrite> SchemaWrite for $target<$key>
1104        where
1105            $key::Src: Sized,
1106        {
1107            type Src = $target<$key::Src>;
1108
1109            #[inline]
1110            fn size_of(src: &Self::Src) -> WriteResult<usize> {
1111                size_of_elem_iter::<$key, BincodeLen>(src.iter())
1112            }
1113
1114            #[inline]
1115            fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
1116                write_elem_iter::<$key, BincodeLen>(writer, src.iter())
1117            }
1118        }
1119
1120        #[cfg(feature = $feature)]
1121        impl<'de, $key> SchemaRead<'de> for $target<$key>
1122        where
1123            $key: SchemaRead<'de>
1124            $(,$key::Dst: $constraint+)*,
1125        {
1126            type Dst = $target<$key::Dst>;
1127
1128            #[inline]
1129            fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1130                let len = <BincodeLen>::read::<$key::Dst>(reader)?;
1131
1132                let map = match $key::TYPE_META {
1133                    TypeMeta::Static { size, .. } => {
1134                        #[allow(clippy::arithmetic_side_effects)]
1135                        // SAFETY: `$key::TYPE_META` specifies a static size, so `len` reads of `T::Dst`
1136                        // will consume `size * len` bytes, fully consuming the trusted window.
1137                        let reader = &mut unsafe { reader.as_trusted_for(size * len) }?;
1138                        let mut set = $with_capacity(len);
1139                        for _ in 0..len {
1140                            set.$insert($key::get(reader)?);
1141                        }
1142                        set
1143                    }
1144                    TypeMeta::Dynamic => {
1145                        let mut set = $with_capacity(len);
1146                        for _ in 0..len {
1147                            set.$insert($key::get(reader)?);
1148                        }
1149                        set
1150                    }
1151                };
1152
1153                dst.write(map);
1154                Ok(())
1155            }
1156        }
1157    };
1158}
1159
1160impl_seq! { "alloc", BTreeMap<K: Ord, V>, |_| BTreeMap::new() }
1161impl_seq! { "std", HashMap<K: Hash | Eq, V>, HashMap::with_capacity }
1162impl_seq! { "alloc", BTreeSet<K: Ord>, |_| BTreeSet::new(), insert }
1163impl_seq! { "std", HashSet<K: Hash | Eq>, HashSet::with_capacity, insert }
1164impl_seq! { "alloc", LinkedList<K:>, |_| LinkedList::new(), push_back }
1165
1166#[cfg(feature = "alloc")]
1167impl<T> SchemaWrite for BinaryHeap<T>
1168where
1169    T: SchemaWrite,
1170    T::Src: Sized,
1171{
1172    type Src = BinaryHeap<T::Src>;
1173
1174    #[inline]
1175    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1176        <containers::BinaryHeap<T, BincodeLen>>::size_of(src)
1177    }
1178
1179    #[inline]
1180    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
1181        <containers::BinaryHeap<T, BincodeLen>>::write(writer, src)
1182    }
1183}
1184
1185#[cfg(feature = "alloc")]
1186impl<'de, T> SchemaRead<'de> for BinaryHeap<T>
1187where
1188    T: SchemaRead<'de>,
1189    T::Dst: Ord,
1190{
1191    type Dst = BinaryHeap<T::Dst>;
1192
1193    #[inline]
1194    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1195        <containers::BinaryHeap<T, BincodeLen>>::read(reader, dst)
1196    }
1197}
1198
1199mod zero_copy {
1200    use {
1201        super::*,
1202        core::slice::{from_raw_parts, from_raw_parts_mut},
1203    };
1204
1205    /// Ensure proper alignment for forming a reference of type `U` from a
1206    /// pointer of type `T`.
1207    ///
1208    /// This should trivially hold for all types supported by the crate,
1209    /// as we only mark zero-copy on `u8`, `i8`, and `[u/i8; N]` types.
1210    /// Additionally, all derived zero-copy types must be comprised entirely
1211    /// of aforementioned align-1 types.
1212    ///
1213    /// Note we include the `align_of > 1` check because it can be DCEd out
1214    /// for types we support (all align `1`).
1215    #[inline(always)]
1216    fn cast_ensure_aligned<T, U>(ptr: *const T) -> ReadResult<*const U> {
1217        let ptr = ptr.cast::<U>();
1218        if align_of::<U>() > 1 && !ptr.is_aligned() {
1219            return Err(unaligned_pointer_read());
1220        }
1221        Ok(ptr)
1222    }
1223
1224    /// Ensure proper alignment for forming a mutable reference of type `U` from a
1225    /// pointer of type `T`.
1226    ///
1227    /// See [`cast_ensure_aligned`] for more details.
1228    #[inline(always)]
1229    fn cast_ensure_aligned_mut<T, U>(ptr: *mut T) -> ReadResult<*mut U> {
1230        let ptr = ptr.cast::<U>();
1231        if align_of::<U>() > 1 && !ptr.is_aligned() {
1232            return Err(unaligned_pointer_read());
1233        }
1234        Ok(ptr)
1235    }
1236
1237    /// Cast a `&[u8]` to a `&T` of a zero-copy type `T`.
1238    ///
1239    /// Errors if the pointer is not properly aligned for reads of `T`.
1240    ///
1241    /// Note we abstract this into a function because it ensures the lifetime of the
1242    /// returned reference is the same as the input. Otherwise the compiler would
1243    /// accept any lifetime as `'de`. We want to preclude usage of something like
1244    /// `reader.fill_exact`, as its lifetime does not extend past the reader.
1245    ///
1246    /// # Safety
1247    /// - `T` must be a zero-copy type (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1248    /// - `bytes.len()` must be equal to `size_of::<T>()`.
1249    #[inline(always)]
1250    pub(super) unsafe fn cast_slice_to_t<T>(bytes: &[u8]) -> ReadResult<&T> {
1251        debug_assert_eq!(bytes.len(), size_of::<T>());
1252        let ptr = cast_ensure_aligned::<u8, T>(bytes.as_ptr())?;
1253        // SAFETY:
1254        // - The pointer is non-null, properly aligned for `&T`, and the length is valid.
1255        // - T is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1256        let val = unsafe { &*ptr };
1257        Ok(val)
1258    }
1259
1260    /// Cast a `&mut [u8]` to a `&mut T` of a zero-copy type `T`.
1261    ///
1262    /// Like [`cast_slice_to_t`], but for mutable slices.
1263    #[inline(always)]
1264    pub(super) unsafe fn cast_slice_to_t_mut<T>(bytes: &mut [u8]) -> ReadResult<&mut T> {
1265        debug_assert_eq!(bytes.len(), size_of::<T>());
1266        let ptr = cast_ensure_aligned_mut::<u8, T>(bytes.as_mut_ptr())?;
1267        // SAFETY:
1268        // - The pointer is non-null, properly aligned for `&T`, and the length is valid.
1269        // - T is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1270        let val = unsafe { &mut *ptr };
1271        Ok(val)
1272    }
1273
1274    /// Cast a `&[u8]` to a `&[T]` of a zero-copy type `T`.
1275    ///
1276    /// Errors if the pointer is not properly aligned for reads of `T`.
1277    ///
1278    /// Note we abstract this into a function because it ensures the lifetime of the
1279    /// returned reference is the same as the input. Otherwise the compiler would
1280    /// accept any lifetime as `'de`. We want to preclude usage of something like
1281    /// `reader.fill_exact`, as its lifetime does not extend past the reader.
1282    ///
1283    /// # Safety
1284    /// - `T` must be a zero-copy type (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1285    /// - `bytes.len()` must be equal to `len * size_of::<T>()`.
1286    #[inline(always)]
1287    pub(super) unsafe fn cast_slice_to_slice_t<T>(bytes: &[u8], len: usize) -> ReadResult<&[T]> {
1288        debug_assert_eq!(Some(bytes.len()), len.checked_mul(size_of::<T>()));
1289        let ptr = cast_ensure_aligned::<u8, T>(bytes.as_ptr())?;
1290        // SAFETY:
1291        // - The pointer is non-null, properly aligned for `&[T]`, and the length is valid.
1292        // - T is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1293        let slice = unsafe { from_raw_parts(ptr, len) };
1294        Ok(slice)
1295    }
1296
1297    /// Cast a `&mut [u8]` to a `&mut [T]` of a zero-copy type `T`.
1298    ///
1299    /// Like [`cast_slice_to_slice_t`], but for mutable slices.
1300    #[inline(always)]
1301    pub(super) unsafe fn cast_slice_to_slice_t_mut<T>(
1302        bytes: &mut [u8],
1303        len: usize,
1304    ) -> ReadResult<&mut [T]> {
1305        debug_assert_eq!(Some(bytes.len()), len.checked_mul(size_of::<T>()));
1306        let ptr = cast_ensure_aligned_mut::<u8, T>(bytes.as_mut_ptr())?;
1307        // SAFETY:
1308        // - The pointer is non-null, properly aligned for `&[T]`, and the length is valid.
1309        // - T is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1310        let slice = unsafe { from_raw_parts_mut(ptr, len) };
1311        Ok(slice)
1312    }
1313
1314    /// [`TypeMeta`] for `&'de T` where `T` is zero-copy.
1315    pub(super) const fn type_meta_t<'de, T>() -> TypeMeta
1316    where
1317        T: SchemaRead<'de> + ZeroCopy,
1318    {
1319        match T::TYPE_META {
1320            TypeMeta::Static {
1321                size,
1322                zero_copy: true,
1323            } => TypeMeta::Static {
1324                size,
1325                // Note: `&'de T` is NOT zero‑copy in the "raw-bytes representable" sense.
1326                // In this crate, `zero_copy: true` means:
1327                // - The type's in‑memory representation is exactly its serialized bytes.
1328                // - It can be safely initialized by memcpy (no validation, no endianness/layout work).
1329                // - Containers may bulk-copy elements (e.g., Vec/BoxedSlice memcpy fast path for Pod).
1330                // - It can be deserialized by reference to some underlying source bytes.
1331                //
1332                // A _reference_ to a zero-copy type does not meet that contract:
1333                // - `&'de T` is a pointer with provenance/lifetime, not bytes you can memcpy into place.
1334                // - You cannot "initialize a reference" by copying bytes; you must point it at already
1335                //   valid storage of `T`.
1336                // - Advertising `zero_copy: true` here could incorrectly enable memcpy of reference
1337                //   elements (e.g., Vec<&T>), which would be unsound.
1338                //
1339                // We borrow the underlying `T` here, knowing it is zero-copy, but the reference itself
1340                // is never considered zero-copy.
1341                zero_copy: false,
1342            },
1343            // Should be impossible to reach.
1344            _ => panic!("Type is not zero-copy"),
1345        }
1346    }
1347
1348    /// [`TypeMeta`] for &[T] where `T` is zero-copy.
1349    ///
1350    /// Slices are never zero-copy due to length encoding and
1351    /// references by their nature (as mentioned in [`type_meta_t`])
1352    /// are not zero-copy.
1353    pub(super) const fn type_meta_slice<'de, T>() -> TypeMeta
1354    where
1355        T: SchemaRead<'de> + ZeroCopy,
1356    {
1357        match T::TYPE_META {
1358            TypeMeta::Static {
1359                zero_copy: true, ..
1360            } => TypeMeta::Dynamic,
1361            _ => panic!("Type is not zero-copy"),
1362        }
1363    }
1364
1365    /// Read the length of the slice from the [`Reader`] and return it
1366    /// with the total size in bytes of the subsequent serialized data.
1367    ///
1368    /// Total size of the serialized data is the length of the slice
1369    /// multiplied by the size of the element type.
1370    #[inline(always)]
1371    pub(super) fn read_slice_len_checked<'de>(
1372        reader: &mut impl Reader<'de>,
1373        size: usize,
1374    ) -> ReadResult<(usize, usize)> {
1375        let Ok(len): Result<usize, _> = u64::get(reader)?.try_into() else {
1376            return Err(pointer_sized_decode_error());
1377        };
1378        let Some(total_size) = len.checked_mul(size) else {
1379            return Err(read_length_encoding_overflow("usize::MAX"));
1380        };
1381        Ok((len, total_size))
1382    }
1383}
1384
1385impl<'de, T> SchemaRead<'de> for &'de T
1386where
1387    T: SchemaRead<'de> + ZeroCopy,
1388{
1389    type Dst = &'de T::Dst;
1390
1391    const TYPE_META: TypeMeta = zero_copy::type_meta_t::<T>();
1392
1393    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1394        let size = T::TYPE_META.size_assert_zero_copy();
1395        let bytes = reader.borrow_exact(size)?;
1396        // SAFETY:
1397        // - T::Dst is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1398        // - `bytes.len() == size_of::<T::Dst>()`. `borrow_exact` ensures we read exactly `size` bytes.
1399        let val = unsafe { zero_copy::cast_slice_to_t::<T::Dst>(bytes)? };
1400        dst.write(val);
1401        Ok(())
1402    }
1403}
1404
1405impl<'de, T> SchemaRead<'de> for &'de mut T
1406where
1407    T: SchemaRead<'de> + ZeroCopy,
1408{
1409    type Dst = &'de mut T::Dst;
1410
1411    const TYPE_META: TypeMeta = zero_copy::type_meta_t::<T>();
1412
1413    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1414        let size = T::TYPE_META.size_assert_zero_copy();
1415        let bytes = reader.borrow_exact_mut(size)?;
1416        // SAFETY:
1417        // - T::Dst is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1418        // - `bytes.len() == size_of::<T::Dst>()`. `borrow_exact_mut` ensures we read exactly `size` bytes.
1419        let val = unsafe { zero_copy::cast_slice_to_t_mut::<T::Dst>(bytes)? };
1420        dst.write(val);
1421        Ok(())
1422    }
1423}
1424
1425impl<'de, T> SchemaRead<'de> for &'de [T]
1426where
1427    T: SchemaRead<'de> + ZeroCopy,
1428{
1429    type Dst = &'de [T::Dst];
1430
1431    const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T>();
1432
1433    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1434        let size = T::TYPE_META.size_assert_zero_copy();
1435        let (len, total_size) = zero_copy::read_slice_len_checked(reader, size)?;
1436        let bytes = reader.borrow_exact(total_size)?;
1437        // SAFETY:
1438        // - T::Dst is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1439        // - `bytes.len() == len * size_of::<T::Dst>()`.`borrow_exact` ensures we read exactly `len * size` bytes.
1440        let slice = unsafe { zero_copy::cast_slice_to_slice_t::<T::Dst>(bytes, len)? };
1441        dst.write(slice);
1442        Ok(())
1443    }
1444}
1445
1446impl<'de, T> SchemaRead<'de> for &'de mut [T]
1447where
1448    T: SchemaRead<'de> + ZeroCopy,
1449{
1450    type Dst = &'de mut [T::Dst];
1451
1452    const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T>();
1453
1454    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1455        let size = T::TYPE_META.size_assert_zero_copy();
1456        let (len, total_size) = zero_copy::read_slice_len_checked(reader, size)?;
1457        let bytes = reader.borrow_exact_mut(total_size)?;
1458        // SAFETY:
1459        // - T::Dst is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1460        // - `bytes.len() == len * size_of::<T::Dst>()`.`borrow_exact_mut` ensures we read exactly `len * size` bytes.
1461        let slice = unsafe { zero_copy::cast_slice_to_slice_t_mut::<T::Dst>(bytes, len)? };
1462        dst.write(slice);
1463        Ok(())
1464    }
1465}