Skip to main content

wincode/schema/
impls.rs

1//! Blanket implementations for std types.
2#[cfg(all(feature = "alloc", not(feature = "std")))]
3use alloc::borrow::ToOwned;
4#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
5use alloc::sync::Arc;
6use {
7    crate::{
8        TypeMeta,
9        config::{Config, ConfigCore, ZeroCopy},
10        containers::decode_into_slice_t,
11        context,
12        error::{
13            ReadResult, WriteError, WriteResult, invalid_bool_encoding, invalid_char_lead,
14            invalid_tag_encoding, invalid_utf8_encoding, invalid_value, pointer_sized_decode_error,
15            read_length_encoding_overflow, unaligned_pointer_read,
16        },
17        int_encoding::{ByteOrder, Endian, IntEncoding, PlatformEndian},
18        io::{Reader, Writer},
19        len::SeqLen,
20        schema::{
21            SchemaRead, SchemaReadContext, SchemaWrite, size_of_elem_slice, write_elem_slice,
22        },
23        tag_encoding::TagEncoding,
24    },
25    core::{
26        cell::{Cell, RefCell},
27        marker::PhantomData,
28        mem::{MaybeUninit, transmute},
29        net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
30        num::{
31            NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
32            NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
33        },
34        ops::{Bound, Range, RangeInclusive},
35        time::Duration,
36    },
37    pastey::paste,
38};
39#[cfg(feature = "alloc")]
40use {
41    crate::{containers, io::BorrowKind},
42    alloc::{
43        borrow::Cow,
44        boxed::Box,
45        collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
46        rc::Rc,
47        string::String,
48        vec::Vec,
49    },
50    core::mem,
51};
52#[cfg(feature = "std")]
53use {
54    core::hash::{BuildHasher, Hash},
55    std::{
56        collections::{HashMap, HashSet},
57        sync::{Mutex, RwLock},
58        time::{SystemTime, UNIX_EPOCH},
59    },
60};
61
62macro_rules! impl_int_config_dependent {
63    ($($type:ty),*) => {
64        paste! {
65            $(
66                unsafe impl<C: ConfigCore> ZeroCopy<C> for $type where C::IntEncoding: ZeroCopy<C> {}
67
68                unsafe impl<C: ConfigCore> SchemaWrite<C> for $type {
69                    type Src = $type;
70
71                    const TYPE_META: TypeMeta = if C::IntEncoding::STATIC {
72                        TypeMeta::Static {
73                            size: size_of::<$type>(),
74                            zero_copy: C::IntEncoding::ZERO_COPY,
75                        }
76                    } else {
77                        TypeMeta::Dynamic
78                    };
79
80                    #[inline(always)]
81                    fn size_of(src: &Self::Src) -> WriteResult<usize> {
82                        Ok(C::IntEncoding::[<size_of_ $type>](*src))
83                    }
84
85                    #[inline(always)]
86                    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
87                        C::IntEncoding::[<encode_ $type>](*src, writer)
88                    }
89                }
90
91                unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $type {
92                    type Dst = $type;
93
94                    const TYPE_META: TypeMeta = if C::IntEncoding::STATIC {
95                        TypeMeta::Static {
96                            size: size_of::<$type>(),
97                            zero_copy: C::IntEncoding::ZERO_COPY,
98                        }
99                    } else {
100                        TypeMeta::Dynamic
101                    };
102
103                    #[inline(always)]
104                    fn read(
105                        reader: impl Reader<'de>,
106                        dst: &mut MaybeUninit<Self::Dst>,
107                    ) -> ReadResult<()> {
108                        let val = C::IntEncoding::[<decode_ $type>](reader)?;
109                        dst.write(val);
110                        Ok(())
111                    }
112                }
113            )*
114        }
115    };
116}
117
118impl_int_config_dependent!(u16, u32, u64, u128, i16, i32, i64, i128);
119
120/// Implementations for `f32` and `f64` using fixed-width encoding and the
121/// configured byte order.
122///
123/// This matches bincode: floats are always fixed-width, independent of integer
124/// encoding choices.
125/// - Varint saves space when small values map to small bit-patterns. IEEE-754
126///   floats do not have that property, so varint rarely (if ever) helps and costs more.
127/// - Exact bit patterns must round-trip (-0.0, NaN payloads, subnormals), which
128///   fixed-width preserves without extra rules or validation.
129macro_rules! impl_float {
130    ($($ty:ty),*) => {
131        $(
132            unsafe impl<C: ConfigCore> ZeroCopy<C> for $ty where C::ByteOrder: PlatformEndian {}
133
134            unsafe impl<C: ConfigCore> SchemaWrite<C> for $ty {
135                type Src = $ty;
136
137                const TYPE_META: TypeMeta = TypeMeta::Static {
138                    size: size_of::<$ty>(),
139                    #[cfg(target_endian = "big")]
140                    zero_copy: matches!(C::ByteOrder::ENDIAN, Endian::Big),
141                    #[cfg(target_endian = "little")]
142                    zero_copy: matches!(C::ByteOrder::ENDIAN, Endian::Little),
143                };
144
145                #[inline(always)]
146                fn size_of(_val: &Self::Src) -> WriteResult<usize> {
147                    Ok(size_of::<$ty>())
148                }
149
150                #[inline(always)]
151                fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
152                    let bytes = match C::ByteOrder::ENDIAN {
153                        Endian::Big => src.to_be_bytes(),
154                        Endian::Little => src.to_le_bytes(),
155                    };
156                    writer.write(&bytes)?;
157                    Ok(())
158                }
159            }
160
161            unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $ty {
162                type Dst = $ty;
163
164                const TYPE_META: TypeMeta = TypeMeta::Static {
165                    size: size_of::<$ty>(),
166                    #[cfg(target_endian = "big")]
167                    zero_copy: matches!(C::ByteOrder::ENDIAN, Endian::Big),
168                    #[cfg(target_endian = "little")]
169                    zero_copy: matches!(C::ByteOrder::ENDIAN, Endian::Little),
170                };
171
172                #[inline(always)]
173                fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
174                    let bytes = reader.take_array::<{ size_of::<$ty>() }>()?;
175                    let val = match C::ByteOrder::ENDIAN {
176                        Endian::Big => <$ty>::from_be_bytes(bytes),
177                        Endian::Little => <$ty>::from_le_bytes(bytes),
178                    };
179                    dst.write(val);
180                    Ok(())
181                }
182            }
183        )*
184    };
185}
186
187impl_float!(f32, f64);
188
189macro_rules! impl_pointer_width {
190    ($($type:ty => $target:ty),*) => {
191        $(
192            #[cfg(target_pointer_width = "64")]
193            unsafe impl<C: ConfigCore> ZeroCopy<C> for $type where C::IntEncoding: ZeroCopy<C> {}
194
195            unsafe impl<C: ConfigCore> SchemaWrite<C> for $type {
196                type Src = $type;
197
198                const TYPE_META: TypeMeta = if C::IntEncoding::STATIC {
199                    TypeMeta::Static {
200                        size: size_of::<$target>(),
201                        #[cfg(target_pointer_width = "64")]
202                        zero_copy: C::IntEncoding::ZERO_COPY,
203                        #[cfg(not(target_pointer_width = "64"))]
204                        zero_copy: false,
205                    }
206                } else {
207                    TypeMeta::Dynamic
208                };
209
210                #[inline(always)]
211                fn size_of(val: &Self::Src) -> WriteResult<usize> {
212                    <$target as SchemaWrite<C>>::size_of(&(*val as $target))
213                }
214
215                #[inline(always)]
216                fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
217                    <$target as SchemaWrite<C>>::write(writer, &(*src as $target))
218                }
219            }
220
221            unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $type {
222                type Dst = $type;
223
224                const TYPE_META: TypeMeta = if C::IntEncoding::STATIC {
225                    TypeMeta::Static {
226                        size: size_of::<$target>(),
227                        #[cfg(target_pointer_width = "64")]
228                        zero_copy: C::IntEncoding::ZERO_COPY,
229                        #[cfg(not(target_pointer_width = "64"))]
230                        zero_copy: false,
231                    }
232                } else {
233                    TypeMeta::Dynamic
234                };
235
236                #[inline(always)]
237                fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
238                    let target = <$target as SchemaRead<C>>::get(reader)?;
239                    let val = target.try_into().map_err(|_| pointer_sized_decode_error())?;
240                    dst.write(val);
241                    Ok(())
242                }
243            }
244        )*
245    };
246}
247
248impl_pointer_width!(usize => u64, isize => i64);
249
250macro_rules! impl_byte {
251    ($($type:ty),*) => {
252        $(
253            // SAFETY:
254            // - canonical zero-copy type: no endianness, no layout, no validation.
255            unsafe impl<C: ConfigCore> ZeroCopy<C> for $type {}
256
257            unsafe impl<C: ConfigCore> SchemaWrite<C> for $type {
258                type Src = $type;
259
260                const TYPE_META: TypeMeta = TypeMeta::Static {
261                    size: size_of::<$type>(),
262                    zero_copy: true,
263                };
264
265                #[inline(always)]
266                fn size_of(_val: &Self::Src) -> WriteResult<usize> {
267                    Ok(size_of::<$type>())
268                }
269
270                #[inline(always)]
271                fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
272                    writer.write(&[*src as u8])?;
273                    Ok(())
274                }
275            }
276
277            unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $type {
278                type Dst = $type;
279
280                const TYPE_META: TypeMeta = TypeMeta::Static {
281                    size: size_of::<$type>(),
282                    zero_copy: true,
283                };
284
285                #[inline(always)]
286                fn read(
287                    mut reader: impl Reader<'de>,
288                    dst: &mut MaybeUninit<Self::Dst>,
289                ) -> ReadResult<()> {
290                    let byte = reader.take_array::<{ 1 }>()?;
291                    dst.write(byte[0] as $type);
292                    Ok(())
293                }
294            }
295        )*
296    };
297}
298
299impl_byte!(u8, i8);
300
301unsafe impl<C: ConfigCore> SchemaWrite<C> for bool {
302    type Src = bool;
303
304    const TYPE_META: TypeMeta = TypeMeta::Static {
305        size: size_of::<bool>(),
306        zero_copy: false,
307    };
308
309    #[inline]
310    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
311        Ok(size_of::<u8>())
312    }
313
314    #[inline]
315    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
316        unsafe { Ok(writer.write_t(&(*src as u8))?) }
317    }
318}
319
320unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for bool {
321    type Dst = bool;
322
323    const TYPE_META: TypeMeta = TypeMeta::Static {
324        size: size_of::<bool>(),
325        zero_copy: false,
326    };
327
328    #[inline]
329    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
330        // SAFETY: u8 is plain ol' data.
331        let byte = <u8 as SchemaRead<'de, C>>::get(reader)?;
332        match byte {
333            0 => {
334                dst.write(false);
335            }
336            1 => {
337                dst.write(true);
338            }
339            _ => return Err(invalid_bool_encoding(byte)),
340        }
341        Ok(())
342    }
343}
344
345unsafe impl<C: ConfigCore> SchemaWrite<C> for char {
346    type Src = char;
347
348    #[inline]
349    fn size_of(src: &Self::Src) -> WriteResult<usize> {
350        let mut buf = [0; 4];
351        let str = src.encode_utf8(&mut buf);
352        Ok(str.len())
353    }
354
355    #[inline]
356    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
357        let mut buf = [0; 4];
358        let str = src.encode_utf8(&mut buf);
359        writer.write(str.as_bytes())?;
360        Ok(())
361    }
362}
363
364unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for char {
365    type Dst = char;
366
367    #[inline]
368    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
369        use crate::error::ReadError;
370
371        // We re-validate with from_utf8 only on error path to get proper Utf8Error.
372        #[cold]
373        fn utf8_error(buf: &[u8]) -> ReadError {
374            invalid_utf8_encoding(core::str::from_utf8(buf).unwrap_err())
375        }
376        let b0 = reader.take_byte()?;
377        let code_point = match b0 {
378            0x00..=0x7F => {
379                dst.write(b0 as char);
380                return Ok(());
381            }
382            0xC2..=0xDF => {
383                let b1 = reader.take_byte()?;
384                // Validate continuation byte (must be 10xxxxxx)
385                if (b1 & 0xC0) != 0x80 {
386                    return Err(utf8_error(&[b0, b1]));
387                }
388                ((b0 & 0x1F) as u32) << 6 | ((b1 & 0x3F) as u32)
389            }
390            0xE0..=0xEF => {
391                let [b1, b2] = reader.take_array()?;
392                if (b1 & 0xC0) != 0x80 || (b2 & 0xC0) != 0x80 {
393                    return Err(utf8_error(&[b0, b1, b2]));
394                }
395                // Check for overlong encodings (< U+0800) and surrogates (U+D800..U+DFFF)
396                if (b0 == 0xE0 && b1 < 0xA0) || (b0 == 0xED && b1 >= 0xA0) {
397                    return Err(utf8_error(&[b0, b1, b2]));
398                }
399                ((b0 & 0x0F) as u32) << 12 | ((b1 & 0x3F) as u32) << 6 | ((b2 & 0x3F) as u32)
400            }
401            0xF0..=0xF4 => {
402                let [b1, b2, b3] = reader.take_array()?;
403                if (b1 & 0xC0) != 0x80 || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 {
404                    return Err(utf8_error(&[b0, b1, b2, b3]));
405                }
406                if (b0 == 0xF0 && b1 < 0x90) || (b0 == 0xF4 && b1 > 0x8F) {
407                    return Err(utf8_error(&[b0, b1, b2, b3]));
408                }
409                ((b0 & 0x07) as u32) << 18
410                    | ((b1 & 0x3F) as u32) << 12
411                    | ((b2 & 0x3F) as u32) << 6
412                    | ((b3 & 0x3F) as u32)
413            }
414            _ => return Err(invalid_char_lead(b0)),
415        };
416
417        let c = char::from_u32(code_point).ok_or(ReadError::InvalidUtf8Code(code_point))?;
418        dst.write(c);
419        Ok(())
420    }
421}
422
423unsafe impl<T, C: ConfigCore> SchemaWrite<C> for PhantomData<T> {
424    type Src = PhantomData<T>;
425
426    const TYPE_META: TypeMeta = TypeMeta::Static {
427        size: 0,
428        zero_copy: true,
429    };
430
431    #[inline]
432    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
433        Ok(0)
434    }
435
436    #[inline]
437    fn write(_writer: impl Writer, _src: &Self::Src) -> WriteResult<()> {
438        Ok(())
439    }
440}
441
442unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for PhantomData<T> {
443    type Dst = PhantomData<T>;
444
445    const TYPE_META: TypeMeta = TypeMeta::Static {
446        size: 0,
447        zero_copy: true,
448    };
449
450    #[inline]
451    fn read(_reader: impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
452        Ok(())
453    }
454}
455
456unsafe impl<C: ConfigCore> SchemaWrite<C> for () {
457    type Src = ();
458
459    const TYPE_META: TypeMeta = TypeMeta::Static {
460        size: 0,
461        zero_copy: true,
462    };
463
464    #[inline]
465    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
466        Ok(0)
467    }
468
469    #[inline]
470    fn write(_writer: impl Writer, _src: &Self::Src) -> WriteResult<()> {
471        Ok(())
472    }
473}
474
475unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for () {
476    type Dst = ();
477
478    const TYPE_META: TypeMeta = TypeMeta::Static {
479        size: 0,
480        zero_copy: true,
481    };
482
483    #[inline]
484    fn read(_reader: impl Reader<'de>, _dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
485        Ok(())
486    }
487}
488
489#[cfg(feature = "alloc")]
490unsafe impl<T, C: Config> SchemaWrite<C> for Vec<T>
491where
492    T: SchemaWrite<C>,
493    T::Src: Sized,
494{
495    type Src = Vec<T::Src>;
496
497    #[inline]
498    fn size_of(value: &Self::Src) -> WriteResult<usize> {
499        <containers::Vec<T, C::LengthEncoding>>::size_of(value)
500    }
501
502    #[inline]
503    fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
504        <containers::Vec<T, C::LengthEncoding>>::write(writer, value)
505    }
506}
507
508#[cfg(feature = "alloc")]
509unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Vec<T>
510where
511    T: SchemaRead<'de, C>,
512{
513    type Dst = Vec<T::Dst>;
514
515    #[inline]
516    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
517        <containers::Vec<T, C::LengthEncoding>>::read(reader, dst)
518    }
519}
520
521#[cfg(feature = "alloc")]
522unsafe impl<'de, T, C: ConfigCore> SchemaReadContext<'de, C, context::Len> for Vec<T>
523where
524    T: SchemaRead<'de, C>,
525{
526    type Dst = Vec<T::Dst>;
527
528    #[inline]
529    fn read_with_context(
530        ctx: context::Len,
531        mut reader: impl Reader<'de>,
532        dst: &mut MaybeUninit<Self::Dst>,
533    ) -> ReadResult<()> {
534        let len = ctx.0;
535        let mut vec = Vec::with_capacity(len);
536        decode_into_slice_t::<T, C>(reader.by_ref(), &mut vec.spare_capacity_mut()[..len])?;
537        // SAFETY: `decode_into_slice_t` initializes all `len` elements on success.
538        unsafe { vec.set_len(len) };
539        dst.write(vec);
540        Ok(())
541    }
542}
543
544#[cfg(feature = "alloc")]
545unsafe impl<T, C: Config> SchemaWrite<C> for VecDeque<T>
546where
547    T: SchemaWrite<C>,
548    T::Src: Sized,
549{
550    type Src = VecDeque<T::Src>;
551
552    #[inline]
553    fn size_of(value: &Self::Src) -> WriteResult<usize> {
554        <containers::VecDeque<T, C::LengthEncoding>>::size_of(value)
555    }
556
557    #[inline]
558    fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
559        <containers::VecDeque<T, C::LengthEncoding>>::write(writer, value)
560    }
561}
562
563#[cfg(feature = "alloc")]
564unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for VecDeque<T>
565where
566    T: SchemaRead<'de, C>,
567{
568    type Dst = VecDeque<T::Dst>;
569
570    #[inline]
571    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
572        <containers::VecDeque<T, C::LengthEncoding>>::read(reader, dst)
573    }
574}
575
576unsafe impl<T, C: Config> SchemaWrite<C> for [T]
577where
578    T: SchemaWrite<C>,
579    T::Src: Sized,
580{
581    type Src = [T::Src];
582
583    #[inline]
584    fn size_of(value: &Self::Src) -> WriteResult<usize> {
585        size_of_elem_slice::<T, C::LengthEncoding, C>(value)
586    }
587
588    #[inline]
589    fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
590        write_elem_slice::<T, C::LengthEncoding, C>(writer, value)
591    }
592}
593
594// SAFETY:
595// - [T; N] where T: ZeroCopy is trivially zero-copy. The length is constant,
596//   so there is no length encoding.
597unsafe impl<const N: usize, C: ConfigCore, T> ZeroCopy<C> for [T; N] where T: ZeroCopy<C> {}
598
599unsafe impl<'de, T, const N: usize, C: ConfigCore> SchemaRead<'de, C> for [T; N]
600where
601    T: SchemaRead<'de, C>,
602{
603    type Dst = [T::Dst; N];
604
605    const TYPE_META: TypeMeta = const {
606        match T::TYPE_META {
607            TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
608                size: N * size,
609                zero_copy,
610            },
611            TypeMeta::Dynamic => TypeMeta::Dynamic,
612        }
613    };
614
615    #[inline]
616    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
617        // SAFETY: MaybeUninit<[T::Dst; N]> trivially converts to [MaybeUninit<T::Dst>; N].
618        let dst =
619            unsafe { transmute::<&mut MaybeUninit<Self::Dst>, &mut [MaybeUninit<T::Dst>; N]>(dst) };
620        decode_into_slice_t::<T, C>(reader, dst)
621    }
622}
623
624unsafe impl<T, const N: usize, C: ConfigCore> SchemaWrite<C> for [T; N]
625where
626    T: SchemaWrite<C>,
627    T::Src: Sized,
628{
629    type Src = [T::Src; N];
630
631    const TYPE_META: TypeMeta = const {
632        match T::TYPE_META {
633            TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
634                size: N * size,
635                zero_copy,
636            },
637            TypeMeta::Dynamic => TypeMeta::Dynamic,
638        }
639    };
640
641    #[inline]
642    #[allow(clippy::arithmetic_side_effects)]
643    fn size_of(value: &Self::Src) -> WriteResult<usize> {
644        if let TypeMeta::Static { size, .. } = Self::TYPE_META {
645            return Ok(size);
646        }
647        // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
648        value
649            .iter()
650            .map(T::size_of)
651            .try_fold(0usize, |acc, x| x.map(|x| acc + x))
652    }
653
654    #[inline]
655    fn write(mut writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
656        match Self::TYPE_META {
657            TypeMeta::Static {
658                zero_copy: true, ..
659            } => {
660                // SAFETY: `T::Src` is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
661                unsafe { writer.write_slice_t(value)? };
662            }
663            TypeMeta::Static {
664                size,
665                zero_copy: false,
666            } => {
667                // SAFETY: `Self::TYPE_META` specifies a static size, which is `N * static_size_of(T)`.
668                // `N` writes of `T` will write `size` bytes, fully initializing the trusted window.
669                let mut writer = unsafe { writer.as_trusted_for(size) }?;
670                for item in value {
671                    T::write(writer.by_ref(), item)?;
672                }
673                writer.finish()?;
674            }
675            TypeMeta::Dynamic => {
676                for item in value {
677                    T::write(writer.by_ref(), item)?;
678                }
679            }
680        }
681
682        Ok(())
683    }
684}
685
686unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for Option<T>
687where
688    T: SchemaRead<'de, C>,
689{
690    type Dst = Option<T::Dst>;
691
692    #[inline]
693    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
694        let variant = <u8 as SchemaRead<'de, C>>::get(reader.by_ref())?;
695        match variant {
696            0 => dst.write(Option::None),
697            1 => dst.write(Option::Some(T::get(reader)?)),
698            _ => return Err(invalid_tag_encoding(variant as usize)),
699        };
700
701        Ok(())
702    }
703}
704
705unsafe impl<T, C: ConfigCore> SchemaWrite<C> for Option<T>
706where
707    T: SchemaWrite<C>,
708    T::Src: Sized,
709{
710    type Src = Option<T::Src>;
711
712    #[inline]
713    #[allow(clippy::arithmetic_side_effects)]
714    fn size_of(src: &Self::Src) -> WriteResult<usize> {
715        match src {
716            // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
717            Option::Some(value) => Ok(1 + T::size_of(value)?),
718            Option::None => Ok(1),
719        }
720    }
721
722    #[inline]
723    fn write(mut writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
724        match value {
725            Option::Some(value) => {
726                <u8 as SchemaWrite<C>>::write(writer.by_ref(), &1)?;
727                T::write(writer, value)
728            }
729            Option::None => <u8 as SchemaWrite<C>>::write(writer, &0),
730        }
731    }
732}
733
734unsafe impl<'de, T, E, C: Config> SchemaRead<'de, C> for Result<T, E>
735where
736    T: SchemaRead<'de, C>,
737    E: SchemaRead<'de, C>,
738{
739    type Dst = Result<T::Dst, E::Dst>;
740
741    const TYPE_META: TypeMeta = match (
742        T::TYPE_META,
743        E::TYPE_META,
744        <C::TagEncoding as SchemaRead<C>>::TYPE_META,
745    ) {
746        (
747            TypeMeta::Static { size: t_size, .. },
748            TypeMeta::Static { size: e_size, .. },
749            TypeMeta::Static {
750                size: disc_size, ..
751            },
752        ) if t_size == e_size => TypeMeta::Static {
753            size: disc_size + t_size,
754            zero_copy: false,
755        },
756        _ => TypeMeta::Dynamic,
757    };
758
759    #[inline]
760    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
761        let disc = C::TagEncoding::try_into_u32(C::TagEncoding::get(reader.by_ref())?)?;
762        match disc {
763            0 => dst.write(Result::Ok(T::get(reader)?)),
764            1 => dst.write(Result::Err(E::get(reader)?)),
765            _ => return Err(invalid_tag_encoding(disc as usize)),
766        };
767
768        Ok(())
769    }
770}
771
772unsafe impl<T, E, C: Config> SchemaWrite<C> for Result<T, E>
773where
774    T: SchemaWrite<C>,
775    E: SchemaWrite<C>,
776    T::Src: Sized,
777    E::Src: Sized,
778{
779    type Src = Result<T::Src, E::Src>;
780
781    const TYPE_META: TypeMeta = match (
782        T::TYPE_META,
783        E::TYPE_META,
784        <C::TagEncoding as SchemaWrite<C>>::TYPE_META,
785    ) {
786        (
787            TypeMeta::Static { size: t_size, .. },
788            TypeMeta::Static { size: e_size, .. },
789            TypeMeta::Static {
790                size: disc_size, ..
791            },
792        ) if t_size == e_size => TypeMeta::Static {
793            size: disc_size + t_size,
794            zero_copy: false,
795        },
796        _ => TypeMeta::Dynamic,
797    };
798
799    #[inline]
800    #[allow(clippy::arithmetic_side_effects)]
801    fn size_of(src: &Self::Src) -> WriteResult<usize> {
802        match src {
803            // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
804            Result::Ok(value) => Ok(C::TagEncoding::size_of_from_u32(0)? + T::size_of(value)?),
805            Result::Err(error) => Ok(C::TagEncoding::size_of_from_u32(1)? + E::size_of(error)?),
806        }
807    }
808
809    #[inline]
810    fn write(mut writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
811        match value {
812            Result::Ok(value) => {
813                C::TagEncoding::write_from_u32(writer.by_ref(), 0)?;
814                T::write(writer, value)
815            }
816            Result::Err(error) => {
817                C::TagEncoding::write_from_u32(writer.by_ref(), 1)?;
818                E::write(writer, error)
819            }
820        }
821    }
822}
823
824unsafe impl<'a, T, C: ConfigCore> SchemaWrite<C> for &'a T
825where
826    T: SchemaWrite<C>,
827    T: ?Sized,
828{
829    type Src = &'a T::Src;
830
831    const TYPE_META: TypeMeta = T::TYPE_META;
832
833    #[inline]
834    fn size_of(src: &Self::Src) -> WriteResult<usize> {
835        T::size_of(*src)
836    }
837
838    #[inline]
839    fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
840        T::write(writer, *value)
841    }
842}
843
844macro_rules! impl_heap_container {
845    ($container:ident) => {
846        #[cfg(feature = "alloc")]
847        unsafe impl<T, C: ConfigCore> SchemaWrite<C> for $container<T>
848        where
849            T: SchemaWrite<C>,
850        {
851            type Src = $container<T::Src>;
852
853            const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
854
855            #[inline]
856            fn size_of(src: &Self::Src) -> WriteResult<usize> {
857                T::size_of(src)
858            }
859
860            #[inline]
861            fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
862                T::write(writer, value)
863            }
864        }
865
866        #[cfg(feature = "alloc")]
867        unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for $container<T>
868        where
869            T: SchemaRead<'de, C>,
870        {
871            type Dst = $container<T::Dst>;
872
873            const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
874
875            #[inline]
876            fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
877                struct DropGuard<T>(*mut MaybeUninit<T>);
878                impl<T> Drop for DropGuard<T> {
879                    #[inline]
880                    fn drop(&mut self) {
881                        drop(unsafe { $container::from_raw(self.0) });
882                    }
883                }
884
885                let mem = $container::<T::Dst>::new_uninit();
886                let ptr = $container::into_raw(mem) as *mut _;
887                let guard: DropGuard<T::Dst> = DropGuard(ptr);
888                T::read(reader, unsafe { &mut *ptr })?;
889
890                mem::forget(guard);
891
892                unsafe {
893                    // SAFETY: `T::read` must properly initialize the `T::Dst`.
894                    dst.write($container::from_raw(ptr).assume_init());
895                }
896                Ok(())
897            }
898        }
899    };
900}
901
902impl_heap_container!(Box);
903impl_heap_container!(Rc);
904#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
905impl_heap_container!(Arc);
906
907#[cfg(feature = "alloc")]
908unsafe impl<T, C: Config> SchemaWrite<C> for Box<[T]>
909where
910    T: SchemaWrite<C>,
911    T::Src: Sized,
912{
913    type Src = Box<[T::Src]>;
914
915    #[inline]
916    fn size_of(src: &Self::Src) -> WriteResult<usize> {
917        <containers::Box<[T], C::LengthEncoding>>::size_of(src)
918    }
919
920    #[inline]
921    fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
922        <containers::Box<[T], C::LengthEncoding>>::write(writer, value)
923    }
924}
925
926#[cfg(feature = "alloc")]
927unsafe impl<T, C: Config> SchemaWrite<C> for Rc<[T]>
928where
929    T: SchemaWrite<C>,
930    T::Src: Sized,
931{
932    type Src = Rc<[T::Src]>;
933
934    #[inline]
935    fn size_of(src: &Self::Src) -> WriteResult<usize> {
936        <containers::Rc<[T], C::LengthEncoding>>::size_of(src)
937    }
938
939    #[inline]
940    fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
941        <containers::Rc<[T], C::LengthEncoding>>::write(writer, value)
942    }
943}
944
945#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
946unsafe impl<T, C: Config> SchemaWrite<C> for Arc<[T]>
947where
948    T: SchemaWrite<C>,
949    T::Src: Sized,
950{
951    type Src = Arc<[T::Src]>;
952
953    #[inline]
954    fn size_of(src: &Self::Src) -> WriteResult<usize> {
955        <containers::Arc<[T], C::LengthEncoding>>::size_of(src)
956    }
957
958    #[inline]
959    fn write(writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
960        <containers::Arc<[T], C::LengthEncoding>>::write(writer, value)
961    }
962}
963
964#[cfg(feature = "alloc")]
965unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Box<[T]>
966where
967    T: SchemaRead<'de, C>,
968{
969    type Dst = Box<[T::Dst]>;
970
971    #[inline]
972    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
973        <containers::Box<[T], C::LengthEncoding>>::read(reader, dst)
974    }
975}
976
977#[cfg(feature = "alloc")]
978unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Rc<[T]>
979where
980    T: SchemaRead<'de, C>,
981{
982    type Dst = Rc<[T::Dst]>;
983
984    #[inline]
985    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
986        <containers::Rc<[T], C::LengthEncoding>>::read(reader, dst)
987    }
988}
989
990#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
991unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Arc<[T]>
992where
993    T: SchemaRead<'de, C>,
994{
995    type Dst = Arc<[T::Dst]>;
996
997    #[inline]
998    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
999        <containers::Arc<[T], C::LengthEncoding>>::read(reader, dst)
1000    }
1001}
1002
1003unsafe impl<C: Config> SchemaWrite<C> for str {
1004    type Src = str;
1005
1006    #[inline]
1007    #[allow(clippy::arithmetic_side_effects)]
1008    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1009        // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
1010        Ok(C::LengthEncoding::write_bytes_needed(src.len())? + src.len())
1011    }
1012
1013    #[inline]
1014    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1015        C::LengthEncoding::write(writer.by_ref(), src.len())?;
1016        writer.write(src.as_bytes())?;
1017        Ok(())
1018    }
1019}
1020
1021#[cfg(feature = "alloc")]
1022unsafe impl<C: Config> SchemaWrite<C> for String {
1023    type Src = String;
1024
1025    #[inline]
1026    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1027        <str as SchemaWrite<C>>::size_of(src)
1028    }
1029
1030    #[inline]
1031    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1032        C::LengthEncoding::prealloc_check::<u8>(src.len())?;
1033        <str as SchemaWrite<C>>::write(writer, src)
1034    }
1035}
1036
1037unsafe impl<'de, C: Config> SchemaRead<'de, C> for &'de str {
1038    type Dst = &'de str;
1039
1040    #[inline]
1041    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1042        let len = C::LengthEncoding::read(reader.by_ref())?;
1043        <&'de str as SchemaReadContext<C, _>>::read_with_context(context::Len(len), reader, dst)
1044    }
1045}
1046
1047unsafe impl<'de, C: ConfigCore> SchemaReadContext<'de, C, context::Len> for &'de str {
1048    type Dst = &'de str;
1049
1050    #[inline]
1051    fn read_with_context(
1052        context::Len(len): context::Len,
1053        mut reader: impl Reader<'de>,
1054        dst: &mut MaybeUninit<Self::Dst>,
1055    ) -> ReadResult<()> {
1056        let bytes = reader.take_borrowed(len)?;
1057        match core::str::from_utf8(bytes) {
1058            Ok(s) => {
1059                dst.write(s);
1060                Ok(())
1061            }
1062            Err(e) => Err(invalid_utf8_encoding(e)),
1063        }
1064    }
1065}
1066
1067#[cfg(feature = "alloc")]
1068unsafe impl<'de, C: Config> SchemaRead<'de, C> for String {
1069    type Dst = String;
1070
1071    #[inline]
1072    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1073        let len = C::LengthEncoding::read_prealloc_check::<u8>(reader.by_ref())?;
1074        <String as SchemaReadContext<C, _>>::read_with_context(context::Len(len), reader, dst)
1075    }
1076}
1077
1078#[cfg(feature = "alloc")]
1079unsafe impl<'de, C: Config> SchemaReadContext<'de, C, context::Len> for String {
1080    type Dst = String;
1081
1082    #[inline]
1083    fn read_with_context(
1084        ctx: context::Len,
1085        reader: impl Reader<'de>,
1086        dst: &mut MaybeUninit<Self::Dst>,
1087    ) -> ReadResult<()> {
1088        let bytes = <Vec<u8> as SchemaReadContext<C, _>>::get_with_context(ctx, reader)?;
1089        match String::from_utf8(bytes) {
1090            Ok(s) => {
1091                dst.write(s);
1092                Ok(())
1093            }
1094            Err(e) => Err(invalid_utf8_encoding(e.utf8_error())),
1095        }
1096    }
1097}
1098
1099/// Implement `SchemaWrite` and `SchemaRead` for types that may be iterated over sequentially.
1100///
1101/// Generally this should only be used on types for which we cannot provide an optimized implementation,
1102/// and where the most optimal implementation is simply iterating over the type to write or collecting
1103/// to read -- typically non-contiguous sequences like `HashMap` or `BTreeMap` (or their set variants).
1104macro_rules! impl_seq_kv {
1105    ($feature: literal,
1106     $target: ident<$key: ident : $($constraint:path)|*, $value: ident $(, $state:ident : $($state_constraint:path)|* )?>,
1107     $with_capacity: expr) => {
1108        #[cfg(feature = $feature)]
1109        unsafe impl<C: $crate::config::Config, $key, $value $(, $state)?> $crate::schema::SchemaWrite<C> for $target<$key, $value $(, $state)?>
1110        where
1111            $key: $crate::schema::SchemaWrite<C>,
1112            $key::Src: Sized,
1113            $value: $crate::schema::SchemaWrite<C>,
1114            $value::Src: Sized
1115            $($(, $state: $state_constraint+)*)?
1116        {
1117            type Src = $target<$key::Src, $value::Src $(, $state)?>;
1118
1119            #[inline]
1120            #[allow(clippy::arithmetic_side_effects)]
1121            fn size_of(src: &Self::Src) -> $crate::error::WriteResult<usize> {
1122                if let ($crate::TypeMeta::Static { size: key_size, .. }, $crate::TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
1123                    return Ok(C::LengthEncoding::write_bytes_needed(src.len())? + (key_size + value_size) * src.len());
1124                }
1125                Ok(C::LengthEncoding::write_bytes_needed(src.len())? +
1126                    src
1127                        .iter()
1128                        .try_fold(
1129                            0usize,
1130                            |acc, (k, v)|
1131                            Ok::<_, $crate::error::WriteError>(
1132                                acc
1133                                + $key::size_of(k)?
1134                                + $value::size_of(v)?
1135                            )
1136                    )?
1137                )
1138            }
1139
1140            #[inline]
1141            fn write(mut writer: impl $crate::io::Writer, src: &Self::Src) -> $crate::error::WriteResult<()> {
1142                if let ($crate::TypeMeta::Static { size: key_size, .. }, $crate::TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
1143                    let len = src.len();
1144                    #[allow(clippy::arithmetic_side_effects)]
1145                    let needed = C::LengthEncoding::write_bytes_needed_prealloc_check::<($key, $value)>(len)? + (key_size + value_size) * len;
1146                    // SAFETY: `$key::TYPE_META` and `$value::TYPE_META` specify static sizes, so `len` writes of `($key::Src, $value::Src)`
1147                    // and `<BincodeLen>::write` will write `needed` bytes, fully initializing the trusted window.
1148                    let mut writer = unsafe { writer.as_trusted_for(needed) }?;
1149                    C::LengthEncoding::write(writer.by_ref(), len)?;
1150                    for (k, v) in src.iter() {
1151                        $key::write(writer.by_ref(), k)?;
1152                        $value::write(writer.by_ref(), v)?;
1153                    }
1154                    writer.finish()?;
1155                    return Ok(());
1156                }
1157                C::LengthEncoding::write(writer.by_ref(), src.len())?;
1158                for (k, v) in src.iter() {
1159                    $key::write(writer.by_ref(), k)?;
1160                    $value::write(writer.by_ref(), v)?;
1161                }
1162                Ok(())
1163            }
1164        }
1165
1166        #[cfg(feature = $feature)]
1167        unsafe impl<'de, C: $crate::config::Config, $key, $value $(, $state)?> $crate::schema::SchemaRead<'de, C> for $target<$key, $value $(, $state)?>
1168        where
1169            $key: $crate::schema::SchemaRead<'de, C>,
1170            $value: $crate::schema::SchemaRead<'de, C>
1171            $(,$key::Dst: $constraint+)*
1172            $($(, $state: $state_constraint+)* )?
1173        {
1174            type Dst = $target<$key::Dst, $value::Dst $(, $state)?>;
1175
1176            #[inline]
1177            fn read(mut reader: impl $crate::io::Reader<'de>, dst: &mut core::mem::MaybeUninit<Self::Dst>) -> $crate::error::ReadResult<()> {
1178                let len = C::LengthEncoding::read_prealloc_check::<($key::Dst, $value::Dst)>(reader.by_ref())?;
1179
1180                let map = if let ($crate::TypeMeta::Static { size: key_size, .. }, $crate::TypeMeta::Static { size: value_size, .. }) = ($key::TYPE_META, $value::TYPE_META) {
1181                    // SAFETY: `$key::TYPE_META` and `$value::TYPE_META` specify static sizes, so `len` reads of `($key::Dst, $value::Dst)`
1182                    // will consume `(key_size + value_size) * len` bytes, fully consuming the trusted window.
1183                    let Some(el_size) = key_size.checked_add(value_size) else {
1184                        return Err($crate::error::read_length_encoding_overflow("usize::MAX"));
1185                    };
1186                    let mut reader = unsafe { reader.as_trusted_for_seq(len, el_size) }?;
1187                    let mut map = $with_capacity(len $(, $state::default())?);
1188                    for _ in 0..len {
1189                        let k = $key::get(reader.by_ref())?;
1190                        let v = $value::get(reader.by_ref())?;
1191                        map.insert(k, v);
1192                    }
1193                    map
1194                } else {
1195                    let mut map = $with_capacity(len $(, $state::default())?);
1196                    for _ in 0..len {
1197                        let k = $key::get(reader.by_ref())?;
1198                        let v = $value::get(reader.by_ref())?;
1199                        map.insert(k, v);
1200                    }
1201                    map
1202                };
1203
1204                dst.write(map);
1205                Ok(())
1206            }
1207        }
1208    };
1209}
1210
1211pub(crate) use impl_seq_kv;
1212
1213macro_rules! impl_seq_v {
1214    ($feature: literal,
1215     $target: ident <$key: ident : $($constraint:path)|* $(, $state:ident : $($state_constraint:path)|*)?>,
1216     $with_capacity: expr, $insert: ident) => {
1217        #[cfg(feature = $feature)]
1218        unsafe impl<C: $crate::config::Config, $key: $crate::schema::SchemaWrite<C> $(, $state)?> $crate::schema::SchemaWrite<C> for $target<$key $(, $state)?>
1219        where
1220            $key::Src: Sized
1221            $($(, $state: $state_constraint+)* )?
1222        {
1223            type Src = $target<$key::Src $(, $state)?>;
1224
1225            #[inline]
1226            fn size_of(src: &Self::Src) -> $crate::error::WriteResult<usize> {
1227                $crate::schema::size_of_elem_iter::<$key, C::LengthEncoding, C>(src.iter())
1228            }
1229
1230            #[inline]
1231            fn write(writer: impl $crate::io::Writer, src: &Self::Src) -> $crate::error::WriteResult<()> {
1232                $crate::schema::write_elem_iter_prealloc_check::<$key, C::LengthEncoding, C>(writer, src.iter())
1233            }
1234        }
1235
1236        #[cfg(feature = $feature)]
1237        unsafe impl<'de, C: $crate::config::Config, $key $(, $state)?> $crate::schema::SchemaRead<'de, C> for $target<$key $(, $state)?>
1238        where
1239            $key: $crate::schema::SchemaRead<'de, C>
1240            $(,$key::Dst: $constraint+)*
1241            $($(, $state: $state_constraint+)* )?
1242        {
1243            type Dst = $target<$key::Dst $(, $state)?>;
1244
1245            #[inline]
1246            fn read(mut reader: impl $crate::io::Reader<'de>, dst: &mut core::mem::MaybeUninit<Self::Dst>) -> $crate::error::ReadResult<()> {
1247                let len = C::LengthEncoding::read_prealloc_check::<$key::Dst>(reader.by_ref())?;
1248
1249                let map = match $key::TYPE_META {
1250                    $crate::TypeMeta::Static { size, .. } => {
1251                        // SAFETY: `$key::TYPE_META` specifies a static size, so `len` reads of `T::Dst`
1252                        // will consume `size * len` bytes, fully consuming the trusted window.
1253                        let mut reader = unsafe { reader.as_trusted_for_seq(len, size) }?;
1254                        let mut set = $with_capacity(len $(, $state::default())?);
1255                        for _ in 0..len {
1256                            set.$insert($key::get(reader.by_ref())?);
1257                        }
1258                        set
1259                    }
1260                    $crate::TypeMeta::Dynamic => {
1261                        let mut set = $with_capacity(len $(, $state::default())?);
1262                        for _ in 0..len {
1263                            set.$insert($key::get(reader.by_ref())?);
1264                        }
1265                        set
1266                    }
1267                };
1268
1269                dst.write(map);
1270                Ok(())
1271            }
1272        }
1273    };
1274}
1275
1276pub(crate) use impl_seq_v;
1277
1278impl_seq_kv! { "alloc", BTreeMap<K: Ord, V>, |_| BTreeMap::new() }
1279impl_seq_kv! { "std", HashMap<K: Hash | Eq, V, S: BuildHasher | Default>, HashMap::with_capacity_and_hasher }
1280impl_seq_v! { "alloc", BTreeSet<K: Ord>, |_| BTreeSet::new(), insert }
1281impl_seq_v! { "std", HashSet<K: Hash | Eq, S: BuildHasher | Default>, HashSet::with_capacity_and_hasher, insert }
1282impl_seq_v! { "alloc", LinkedList<K:>, |_| LinkedList::new(), push_back }
1283
1284#[cfg(feature = "alloc")]
1285unsafe impl<T, C: Config> SchemaWrite<C> for BinaryHeap<T>
1286where
1287    T: SchemaWrite<C>,
1288    T::Src: Sized,
1289{
1290    type Src = BinaryHeap<T::Src>;
1291
1292    #[inline]
1293    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1294        <containers::BinaryHeap<T, C::LengthEncoding>>::size_of(src)
1295    }
1296
1297    #[inline]
1298    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1299        <containers::BinaryHeap<T, C::LengthEncoding>>::write(writer, src)
1300    }
1301}
1302
1303#[cfg(feature = "alloc")]
1304unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for BinaryHeap<T>
1305where
1306    T: SchemaRead<'de, C>,
1307    T::Dst: Ord,
1308{
1309    type Dst = BinaryHeap<T::Dst>;
1310
1311    #[inline]
1312    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1313        <containers::BinaryHeap<T, C::LengthEncoding>>::read(reader, dst)
1314    }
1315}
1316
1317mod zero_copy {
1318    use {
1319        super::*,
1320        core::slice::{from_raw_parts, from_raw_parts_mut},
1321    };
1322
1323    /// Ensure proper alignment for forming a reference of type `U` from a
1324    /// pointer of type `T`.
1325    ///
1326    /// This should trivially hold for all types supported by the crate,
1327    /// as we only mark zero-copy on `u8`, `i8`, and `[u/i8; N]` types.
1328    /// Additionally, all derived zero-copy types must be comprised entirely
1329    /// of aforementioned align-1 types.
1330    ///
1331    /// Note we include the `align_of > 1` check because it can be DCEd out
1332    /// for types we support (all align `1`).
1333    #[inline(always)]
1334    fn cast_ensure_aligned<C: ConfigCore, T, U>(ptr: *const T) -> ReadResult<*const U> {
1335        let ptr = ptr.cast::<U>();
1336
1337        if !C::ZERO_COPY_ALIGN_CHECK {
1338            return Ok(ptr);
1339        }
1340
1341        if align_of::<U>() > 1 && !ptr.is_aligned() {
1342            return Err(unaligned_pointer_read());
1343        }
1344        Ok(ptr)
1345    }
1346
1347    /// Ensure proper alignment for forming a mutable reference of type `U` from a
1348    /// pointer of type `T`.
1349    ///
1350    /// See [`cast_ensure_aligned`] for more details.
1351    #[inline(always)]
1352    fn cast_ensure_aligned_mut<C: ConfigCore, T, U>(ptr: *mut T) -> ReadResult<*mut U> {
1353        let ptr = ptr.cast::<U>();
1354
1355        if !C::ZERO_COPY_ALIGN_CHECK {
1356            return Ok(ptr);
1357        }
1358
1359        if align_of::<U>() > 1 && !ptr.is_aligned() {
1360            return Err(unaligned_pointer_read());
1361        }
1362        Ok(ptr)
1363    }
1364
1365    /// Cast a `&[u8]` to a `&T` of a zero-copy type `T`.
1366    ///
1367    /// Errors if the pointer is not properly aligned for reads of `T`.
1368    ///
1369    /// Note we abstract this into a function because it ensures the lifetime of the
1370    /// returned reference is the same as the input. Otherwise the compiler would
1371    /// accept any lifetime as `'de`.
1372    ///
1373    /// # Safety
1374    /// - `T` must be a zero-copy type (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1375    /// - `bytes.len()` must be equal to `size_of::<T>()`.
1376    #[inline(always)]
1377    pub(super) unsafe fn cast_slice_to_t<C: ConfigCore, T>(bytes: &[u8]) -> ReadResult<&T> {
1378        debug_assert_eq!(bytes.len(), size_of::<T>());
1379        let ptr = cast_ensure_aligned::<C, u8, T>(bytes.as_ptr())?;
1380        // SAFETY:
1381        // - The pointer is non-null, properly aligned for `&T`, and the length is valid.
1382        // - T is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1383        let val = unsafe { &*ptr };
1384        Ok(val)
1385    }
1386
1387    /// Cast a `&mut [u8]` to a `&mut T` of a zero-copy type `T`.
1388    ///
1389    /// Like [`cast_slice_to_t`], but for mutable slices.
1390    #[inline(always)]
1391    pub(super) unsafe fn cast_slice_to_t_mut<C: ConfigCore, T>(
1392        bytes: &mut [u8],
1393    ) -> ReadResult<&mut T> {
1394        debug_assert_eq!(bytes.len(), size_of::<T>());
1395        let ptr = cast_ensure_aligned_mut::<C, u8, T>(bytes.as_mut_ptr())?;
1396        // SAFETY:
1397        // - The pointer is non-null, properly aligned for `&T`, and the length is valid.
1398        // - T is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1399        let val = unsafe { &mut *ptr };
1400        Ok(val)
1401    }
1402
1403    /// Cast a `&[u8]` to a `&[T]` of a zero-copy type `T`.
1404    ///
1405    /// Errors if the pointer is not properly aligned for reads of `T`.
1406    ///
1407    /// Note we abstract this into a function because it ensures the lifetime of the
1408    /// returned reference is the same as the input. Otherwise the compiler would
1409    /// accept any lifetime as `'de`.
1410    ///
1411    /// # Safety
1412    /// - `T` must be a zero-copy type (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1413    /// - `bytes.len()` must be equal to `len * size_of::<T>()`.
1414    #[inline(always)]
1415    pub(super) unsafe fn cast_slice_to_slice_t<C: ConfigCore, T>(
1416        bytes: &[u8],
1417        len: usize,
1418    ) -> ReadResult<&[T]> {
1419        debug_assert_eq!(Some(bytes.len()), len.checked_mul(size_of::<T>()));
1420        let ptr = cast_ensure_aligned::<C, u8, T>(bytes.as_ptr())?;
1421        // SAFETY:
1422        // - The pointer is non-null, properly aligned for `&[T]`, and the length is valid.
1423        // - T is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1424        let slice = unsafe { from_raw_parts(ptr, len) };
1425        Ok(slice)
1426    }
1427
1428    /// Cast a `&mut [u8]` to a `&mut [T]` of a zero-copy type `T`.
1429    ///
1430    /// Like [`cast_slice_to_slice_t`], but for mutable slices.
1431    #[inline(always)]
1432    pub(super) unsafe fn cast_slice_to_slice_t_mut<C: ConfigCore, T>(
1433        bytes: &mut [u8],
1434        len: usize,
1435    ) -> ReadResult<&mut [T]> {
1436        debug_assert_eq!(Some(bytes.len()), len.checked_mul(size_of::<T>()));
1437        let ptr = cast_ensure_aligned_mut::<C, u8, T>(bytes.as_mut_ptr())?;
1438        // SAFETY:
1439        // - The pointer is non-null, properly aligned for `&[T]`, and the length is valid.
1440        // - T is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1441        let slice = unsafe { from_raw_parts_mut(ptr, len) };
1442        Ok(slice)
1443    }
1444
1445    /// [`TypeMeta`] for `&'de T` where `T` is zero-copy.
1446    pub(super) const fn type_meta_t<'de, T, C: ConfigCore>() -> TypeMeta
1447    where
1448        T: SchemaRead<'de, C> + ZeroCopy<C>,
1449    {
1450        match T::TYPE_META {
1451            TypeMeta::Static {
1452                size,
1453                zero_copy: true,
1454            } => TypeMeta::Static {
1455                size,
1456                // Note: `&'de T` is NOT zero‑copy in the "raw-bytes representable" sense.
1457                // In this crate, `zero_copy: true` means:
1458                // - The type's in‑memory representation is exactly its serialized bytes.
1459                // - It can be safely initialized by memcpy (no validation, no endianness/layout work).
1460                // - Containers may bulk-copy elements (e.g., Vec/BoxedSlice memcpy fast path).
1461                // - It can be deserialized by reference to some underlying source bytes.
1462                //
1463                // A _reference_ to a zero-copy type does not meet that contract:
1464                // - `&'de T` is a pointer with provenance/lifetime, not bytes you can memcpy into place.
1465                // - You cannot "initialize a reference" by copying bytes; you must point it at already
1466                //   valid storage of `T`.
1467                // - Advertising `zero_copy: true` here could incorrectly enable memcpy of reference
1468                //   elements (e.g., Vec<&T>), which would be unsound.
1469                //
1470                // We borrow the underlying `T` here, knowing it is zero-copy, but the reference itself
1471                // is never considered zero-copy.
1472                zero_copy: false,
1473            },
1474            // Should be impossible to reach.
1475            _ => panic!("Type is not zero-copy"),
1476        }
1477    }
1478
1479    /// [`TypeMeta`] for &[T] where `T` is zero-copy.
1480    ///
1481    /// Slices are never zero-copy due to length encoding and
1482    /// references by their nature (as mentioned in [`type_meta_t`])
1483    /// are not zero-copy.
1484    pub(super) const fn type_meta_slice<'de, T, C: ConfigCore>() -> TypeMeta
1485    where
1486        T: SchemaRead<'de, C> + ZeroCopy<C>,
1487    {
1488        match T::TYPE_META {
1489            TypeMeta::Static {
1490                zero_copy: true, ..
1491            } => TypeMeta::Dynamic,
1492            _ => panic!("Type is not zero-copy"),
1493        }
1494    }
1495
1496    /// Read the length of the slice from the [`Reader`] and return it
1497    /// with the total size in bytes of the subsequent serialized data.
1498    ///
1499    /// Total size of the serialized data is the length of the slice
1500    /// multiplied by the size of the element type.
1501    #[inline(always)]
1502    pub(super) fn read_slice_len_checked<'de, C: Config>(
1503        reader: impl Reader<'de>,
1504        size: usize,
1505    ) -> ReadResult<(usize, usize)> {
1506        let len = C::LengthEncoding::read(reader)?;
1507        let Some(total_size) = len.checked_mul(size) else {
1508            return Err(read_length_encoding_overflow("usize::MAX"));
1509        };
1510        Ok((len, total_size))
1511    }
1512}
1513
1514unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for &'de T
1515where
1516    T: SchemaRead<'de, C> + ZeroCopy<C>,
1517{
1518    type Dst = &'de T::Dst;
1519
1520    const TYPE_META: TypeMeta = zero_copy::type_meta_t::<T, C>();
1521
1522    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1523        let size = T::TYPE_META.size_assert_zero_copy();
1524        let bytes = reader.take_borrowed(size)?;
1525        // SAFETY:
1526        // - T::Dst is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1527        // - `bytes.len() == size_of::<T::Dst>()`. `take_borrowed` ensures we read exactly `size` bytes.
1528        let val = unsafe { zero_copy::cast_slice_to_t::<C, T::Dst>(bytes)? };
1529        dst.write(val);
1530        Ok(())
1531    }
1532}
1533
1534unsafe impl<'de, T, C: ConfigCore> SchemaRead<'de, C> for &'de mut T
1535where
1536    T: SchemaRead<'de, C> + ZeroCopy<C>,
1537{
1538    type Dst = &'de mut T::Dst;
1539
1540    const TYPE_META: TypeMeta = zero_copy::type_meta_t::<T, C>();
1541
1542    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1543        let size = T::TYPE_META.size_assert_zero_copy();
1544        let bytes = reader.take_borrowed_mut(size)?;
1545        // SAFETY:
1546        // - T::Dst is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1547        // - `bytes.len() == size_of::<T::Dst>()`. `take_borrowed_mut` ensures we read exactly `size` bytes.
1548        let val = unsafe { zero_copy::cast_slice_to_t_mut::<C, T::Dst>(bytes)? };
1549        dst.write(val);
1550        Ok(())
1551    }
1552}
1553
1554unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for &'de [T]
1555where
1556    T: SchemaRead<'de, C> + ZeroCopy<C>,
1557{
1558    type Dst = &'de [T::Dst];
1559
1560    const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T, C>();
1561
1562    #[inline]
1563    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1564        let len = C::LengthEncoding::read(reader.by_ref())?;
1565        <&[T]>::read_with_context(context::Len(len), reader, dst)?;
1566        Ok(())
1567    }
1568}
1569
1570unsafe impl<'de, T, C: ConfigCore> SchemaReadContext<'de, C, context::Len> for &'de [T]
1571where
1572    T: SchemaRead<'de, C> + ZeroCopy<C>,
1573{
1574    type Dst = &'de [T::Dst];
1575
1576    const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T, C>();
1577
1578    #[inline]
1579    fn read_with_context(
1580        context::Len(len): context::Len,
1581        mut reader: impl Reader<'de>,
1582        dst: &mut MaybeUninit<Self::Dst>,
1583    ) -> ReadResult<()> {
1584        let size = T::TYPE_META.size_assert_zero_copy();
1585        let Some(total_size) = len.checked_mul(size) else {
1586            return Err(read_length_encoding_overflow("usize::MAX"));
1587        };
1588        let bytes = reader.take_borrowed(total_size)?;
1589        // SAFETY:
1590        // - T::Dst is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1591        // - `bytes.len() == len * size_of::<T::Dst>()`. `take_borrowed` ensures we read exactly `len * size` bytes.
1592        let slice = unsafe { zero_copy::cast_slice_to_slice_t::<C, T::Dst>(bytes, len)? };
1593        dst.write(slice);
1594        Ok(())
1595    }
1596}
1597
1598unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for &'de mut [T]
1599where
1600    T: SchemaRead<'de, C> + ZeroCopy<C>,
1601{
1602    type Dst = &'de mut [T::Dst];
1603
1604    const TYPE_META: TypeMeta = zero_copy::type_meta_slice::<T, C>();
1605
1606    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1607        let size = T::TYPE_META.size_assert_zero_copy();
1608        let (len, total_size) = zero_copy::read_slice_len_checked::<C>(reader.by_ref(), size)?;
1609        let bytes = reader.take_borrowed_mut(total_size)?;
1610        // SAFETY:
1611        // - T::Dst is zero-copy (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
1612        // - `bytes.len() == len * size_of::<T::Dst>()`. `take_borrowed_mut` ensures we read exactly `len * size` bytes.
1613        let slice = unsafe { zero_copy::cast_slice_to_slice_t_mut::<C, T::Dst>(bytes, len)? };
1614        dst.write(slice);
1615        Ok(())
1616    }
1617}
1618
1619unsafe impl<C: ConfigCore> SchemaWrite<C> for Duration {
1620    type Src = Duration;
1621
1622    const TYPE_META: TypeMeta = match (
1623        <u64 as SchemaWrite<C>>::TYPE_META,
1624        <u32 as SchemaWrite<C>>::TYPE_META,
1625    ) {
1626        // both static
1627        (TypeMeta::Static { size: u64_size, .. }, TypeMeta::Static { size: u32_size, .. }) => {
1628            TypeMeta::Static {
1629                size: u64_size + u32_size,
1630                zero_copy: false,
1631            }
1632        }
1633        _ => TypeMeta::Dynamic,
1634    };
1635
1636    #[inline]
1637    #[allow(clippy::arithmetic_side_effects)]
1638    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1639        match <Self as SchemaWrite<C>>::TYPE_META {
1640            TypeMeta::Static { size, .. } => Ok(size),
1641            TypeMeta::Dynamic => {
1642                let secs = <u64 as SchemaWrite<C>>::size_of(&src.as_secs())?;
1643                let nanos = <u32 as SchemaWrite<C>>::size_of(&src.subsec_nanos())?;
1644                Ok(secs + nanos)
1645            }
1646        }
1647    }
1648
1649    #[inline]
1650    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1651        <u64 as SchemaWrite<C>>::write(writer.by_ref(), &src.as_secs())?;
1652        <u32 as SchemaWrite<C>>::write(writer, &src.subsec_nanos())?;
1653        Ok(())
1654    }
1655}
1656
1657unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for Duration {
1658    type Dst = Duration;
1659
1660    const TYPE_META: TypeMeta = <Duration as SchemaWrite<C>>::TYPE_META;
1661
1662    #[inline]
1663    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1664        let secs = <u64 as SchemaRead<'de, C>>::get(reader.by_ref())?;
1665        let nanos = <u32 as SchemaRead<'de, C>>::get(reader)?;
1666        if secs.checked_add(u64::from(nanos) / 1_000_000_000).is_none() {
1667            return Err(invalid_value("Duration overflow"));
1668        }
1669        dst.write(Duration::new(secs, nanos));
1670        Ok(())
1671    }
1672}
1673
1674#[cfg(feature = "std")]
1675unsafe impl<C: ConfigCore> SchemaWrite<C> for SystemTime {
1676    type Src = SystemTime;
1677
1678    const TYPE_META: TypeMeta = <Duration as SchemaWrite<C>>::TYPE_META;
1679
1680    #[inline]
1681    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1682        match <Self as SchemaWrite<C>>::TYPE_META {
1683            TypeMeta::Static { size, .. } => Ok(size),
1684            TypeMeta::Dynamic => {
1685                let duration = src.duration_since(UNIX_EPOCH).map_err(|_| {
1686                    crate::error::WriteError::Custom("SystemTime before UNIX_EPOCH")
1687                })?;
1688                <Duration as SchemaWrite<C>>::size_of(&duration)
1689            }
1690        }
1691    }
1692
1693    #[inline]
1694    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1695        let duration = src
1696            .duration_since(UNIX_EPOCH)
1697            .map_err(|_| crate::error::WriteError::Custom("SystemTime before UNIX_EPOCH"))?;
1698        <Duration as SchemaWrite<C>>::write(writer, &duration)?;
1699        Ok(())
1700    }
1701}
1702
1703#[cfg(feature = "std")]
1704unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for SystemTime {
1705    type Dst = SystemTime;
1706
1707    const TYPE_META: TypeMeta = <Duration as SchemaRead<'de, C>>::TYPE_META;
1708
1709    #[inline]
1710    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1711        let duration = <Duration as SchemaRead<'de, C>>::get(reader)?;
1712        let system_time = UNIX_EPOCH
1713            .checked_add(duration)
1714            .ok_or_else(|| invalid_value("SystemTime overflow"))?;
1715        dst.write(system_time);
1716        Ok(())
1717    }
1718}
1719
1720unsafe impl<C: ConfigCore> SchemaWrite<C> for Ipv4Addr {
1721    type Src = Ipv4Addr;
1722
1723    const TYPE_META: TypeMeta = TypeMeta::Static {
1724        size: 4,
1725        zero_copy: false,
1726    };
1727
1728    #[inline]
1729    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
1730        Ok(4)
1731    }
1732
1733    #[inline]
1734    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1735        writer.write(&src.octets())?;
1736        Ok(())
1737    }
1738}
1739
1740unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for Ipv4Addr {
1741    type Dst = Ipv4Addr;
1742
1743    const TYPE_META: TypeMeta = TypeMeta::Static {
1744        size: 4,
1745        zero_copy: false,
1746    };
1747
1748    #[inline]
1749    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1750        let bytes = reader.take_array::<4>()?;
1751        dst.write(Ipv4Addr::from(bytes));
1752        Ok(())
1753    }
1754}
1755
1756unsafe impl<C: ConfigCore> SchemaWrite<C> for Ipv6Addr {
1757    type Src = Ipv6Addr;
1758
1759    const TYPE_META: TypeMeta = TypeMeta::Static {
1760        size: 16,
1761        zero_copy: false,
1762    };
1763
1764    #[inline]
1765    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
1766        Ok(16)
1767    }
1768
1769    #[inline]
1770    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1771        writer.write(&src.octets())?;
1772        Ok(())
1773    }
1774}
1775
1776unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for Ipv6Addr {
1777    type Dst = Ipv6Addr;
1778
1779    const TYPE_META: TypeMeta = TypeMeta::Static {
1780        size: 16,
1781        zero_copy: false,
1782    };
1783
1784    #[inline]
1785    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1786        let bytes = reader.take_array::<16>()?;
1787        dst.write(Ipv6Addr::from(bytes));
1788        Ok(())
1789    }
1790}
1791
1792unsafe impl<C: Config> SchemaWrite<C> for IpAddr {
1793    type Src = IpAddr;
1794
1795    #[inline]
1796    #[allow(clippy::arithmetic_side_effects)]
1797    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1798        Ok(match src {
1799            IpAddr::V4(_) => C::TagEncoding::size_of_from_u32(0)? + 4,
1800            IpAddr::V6(_) => C::TagEncoding::size_of_from_u32(1)? + 16,
1801        })
1802    }
1803
1804    #[inline]
1805    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1806        match src {
1807            IpAddr::V4(addr) => {
1808                C::TagEncoding::write_from_u32(writer.by_ref(), 0)?;
1809                <Ipv4Addr as SchemaWrite<C>>::write(writer, addr)
1810            }
1811            IpAddr::V6(addr) => {
1812                C::TagEncoding::write_from_u32(writer.by_ref(), 1)?;
1813                <Ipv6Addr as SchemaWrite<C>>::write(writer, addr)
1814            }
1815        }
1816    }
1817}
1818
1819unsafe impl<'de, C: Config> SchemaRead<'de, C> for IpAddr {
1820    type Dst = IpAddr;
1821
1822    #[inline]
1823    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1824        let tag = C::TagEncoding::try_into_u32(C::TagEncoding::get(reader.by_ref())?)?;
1825        match tag {
1826            0 => {
1827                let addr = <Ipv4Addr as SchemaRead<'de, C>>::get(reader)?;
1828                dst.write(IpAddr::V4(addr));
1829                Ok(())
1830            }
1831            1 => {
1832                let addr = <Ipv6Addr as SchemaRead<'de, C>>::get(reader)?;
1833                dst.write(IpAddr::V6(addr));
1834                Ok(())
1835            }
1836            _ => Err(invalid_tag_encoding(tag as usize)),
1837        }
1838    }
1839}
1840
1841unsafe impl<C: ConfigCore> SchemaWrite<C> for SocketAddrV4 {
1842    type Src = Self;
1843
1844    const TYPE_META: TypeMeta = TypeMeta::join_types([
1845        <Ipv4Addr as SchemaWrite<C>>::TYPE_META,
1846        <u16 as SchemaWrite<C>>::TYPE_META,
1847    ]);
1848
1849    #[inline]
1850    #[allow(clippy::arithmetic_side_effects)]
1851    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1852        Ok(4 + <u16 as SchemaWrite<C>>::size_of(&src.port())?)
1853    }
1854
1855    #[inline]
1856    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1857        <Ipv4Addr as SchemaWrite<C>>::write(writer.by_ref(), src.ip())?;
1858        <u16 as SchemaWrite<C>>::write(writer, &src.port())
1859    }
1860}
1861
1862unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for SocketAddrV4 {
1863    type Dst = Self;
1864
1865    const TYPE_META: TypeMeta = TypeMeta::join_types([
1866        <Ipv4Addr as SchemaRead<C>>::TYPE_META,
1867        <u16 as SchemaRead<C>>::TYPE_META,
1868    ]);
1869
1870    #[inline]
1871    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1872        let ip = <Ipv4Addr as SchemaRead<'de, C>>::get(reader.by_ref())?;
1873        let port = <u16 as SchemaRead<'de, C>>::get(reader)?;
1874        dst.write(Self::Dst::new(ip, port));
1875        Ok(())
1876    }
1877}
1878
1879unsafe impl<C: ConfigCore> SchemaWrite<C> for SocketAddrV6 {
1880    type Src = Self;
1881
1882    const TYPE_META: TypeMeta = TypeMeta::join_types([
1883        <Ipv6Addr as SchemaWrite<C>>::TYPE_META,
1884        <u16 as SchemaWrite<C>>::TYPE_META,
1885    ]);
1886
1887    #[inline]
1888    #[allow(clippy::arithmetic_side_effects)]
1889    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1890        Ok(16 + <u16 as SchemaWrite<C>>::size_of(&src.port())?)
1891    }
1892
1893    #[inline]
1894    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1895        <Ipv6Addr as SchemaWrite<C>>::write(writer.by_ref(), src.ip())?;
1896        <u16 as SchemaWrite<C>>::write(writer, &src.port())
1897    }
1898}
1899
1900unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for SocketAddrV6 {
1901    type Dst = Self;
1902
1903    const TYPE_META: TypeMeta = TypeMeta::join_types([
1904        <Ipv6Addr as SchemaRead<C>>::TYPE_META,
1905        <u16 as SchemaRead<C>>::TYPE_META,
1906    ]);
1907
1908    #[inline]
1909    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1910        let ip = <Ipv6Addr as SchemaRead<'de, C>>::get(reader.by_ref())?;
1911        let port = <u16 as SchemaRead<'de, C>>::get(reader)?;
1912        // serde and thus bincode doesn't encode flowinfo and scope_id
1913        dst.write(SocketAddrV6::new(ip, port, 0, 0));
1914        Ok(())
1915    }
1916}
1917
1918unsafe impl<C: Config> SchemaWrite<C> for SocketAddr {
1919    type Src = Self;
1920
1921    #[inline]
1922    #[allow(clippy::arithmetic_side_effects)]
1923    fn size_of(src: &Self::Src) -> WriteResult<usize> {
1924        Ok(match src {
1925            Self::V4(v4) => {
1926                C::TagEncoding::size_of_from_u32(0)?
1927                    + <SocketAddrV4 as SchemaWrite<C>>::size_of(v4)?
1928            }
1929            Self::V6(v6) => {
1930                C::TagEncoding::size_of_from_u32(1)?
1931                    + <SocketAddrV6 as SchemaWrite<C>>::size_of(v6)?
1932            }
1933        })
1934    }
1935
1936    #[inline]
1937    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1938        match src {
1939            Self::V4(addr) => {
1940                C::TagEncoding::write_from_u32(writer.by_ref(), 0)?;
1941                <SocketAddrV4 as SchemaWrite<C>>::write(writer, addr)
1942            }
1943            Self::V6(addr) => {
1944                C::TagEncoding::write_from_u32(writer.by_ref(), 1)?;
1945                <SocketAddrV6 as SchemaWrite<C>>::write(writer, addr)
1946            }
1947        }
1948    }
1949}
1950
1951unsafe impl<'de, C: Config> SchemaRead<'de, C> for SocketAddr {
1952    type Dst = Self;
1953
1954    #[inline]
1955    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
1956        let tag = C::TagEncoding::try_into_u32(C::TagEncoding::get(reader.by_ref())?)?;
1957        match tag {
1958            0 => {
1959                let addr = <SocketAddrV4 as SchemaRead<'de, C>>::get(reader)?;
1960                dst.write(Self::V4(addr));
1961                Ok(())
1962            }
1963            1 => {
1964                let addr = <SocketAddrV6 as SchemaRead<'de, C>>::get(reader)?;
1965                dst.write(Self::V6(addr));
1966                Ok(())
1967            }
1968            _ => Err(invalid_tag_encoding(tag as usize)),
1969        }
1970    }
1971}
1972
1973macro_rules! impl_nonzero {
1974    ($($nonzero_ty:ty => $primitive_ty:ty),* $(,)?) => {
1975        $(
1976            unsafe impl<C: ConfigCore> SchemaWrite<C> for $nonzero_ty {
1977                type Src = $nonzero_ty;
1978
1979                const TYPE_META: TypeMeta = <$primitive_ty as SchemaWrite<C>>::TYPE_META;
1980
1981                #[inline(always)]
1982                fn size_of(src: &Self::Src) -> WriteResult<usize> {
1983                    <$primitive_ty as SchemaWrite<C>>::size_of(&src.get())
1984                }
1985
1986                #[inline(always)]
1987                fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
1988                   <$primitive_ty as SchemaWrite<C>>::write(writer, &src.get())
1989                }
1990            }
1991
1992            unsafe impl<'de, C: ConfigCore> SchemaRead<'de, C> for $nonzero_ty {
1993                type Dst = $nonzero_ty;
1994
1995                const TYPE_META: TypeMeta = const {
1996                    match <$primitive_ty as SchemaRead<'de, C>>::TYPE_META {
1997                        TypeMeta::Static { size, .. } => TypeMeta::Static {
1998                            size,
1999                            zero_copy: false,
2000                        },
2001                        TypeMeta::Dynamic => TypeMeta::Dynamic,
2002                    }
2003                };
2004
2005                #[inline(always)]
2006                fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
2007                    let val = <$primitive_ty as SchemaRead<'de, C>>::get(reader)?;
2008                    let nonzero = <$nonzero_ty>::new(val)
2009                        .ok_or_else(|| invalid_value(concat!(
2010                            "NonZero value cannot be zero for type ",
2011                            stringify!($nonzero_ty)
2012                        )))?;
2013                    dst.write(nonzero);
2014                    Ok(())
2015                }
2016            }
2017        )*
2018    };
2019}
2020
2021impl_nonzero!(
2022    NonZeroU8 => u8,
2023    NonZeroU16 => u16,
2024    NonZeroU32 => u32,
2025    NonZeroU64 => u64,
2026    NonZeroU128 => u128,
2027    NonZeroUsize => usize,
2028    NonZeroI8 => i8,
2029    NonZeroI16 => i16,
2030    NonZeroI32 => i32,
2031    NonZeroI64 => i64,
2032    NonZeroI128 => i128,
2033    NonZeroIsize => isize,
2034);
2035
2036unsafe impl<C: Config, T> SchemaWrite<C> for Bound<T>
2037where
2038    T: SchemaWrite<C>,
2039    T::Src: Sized,
2040{
2041    type Src = Bound<T::Src>;
2042
2043    #[inline]
2044    #[allow(clippy::arithmetic_side_effects)]
2045    fn size_of(src: &Self::Src) -> WriteResult<usize> {
2046        match src {
2047            Bound::Unbounded => C::TagEncoding::size_of_from_u32(0),
2048            Bound::Included(value) => Ok(C::TagEncoding::size_of_from_u32(1)? + T::size_of(value)?),
2049            Bound::Excluded(value) => Ok(C::TagEncoding::size_of_from_u32(2)? + T::size_of(value)?),
2050        }
2051    }
2052
2053    #[inline]
2054    fn write(mut writer: impl Writer, value: &Self::Src) -> WriteResult<()> {
2055        match value {
2056            Bound::Unbounded => C::TagEncoding::write_from_u32(writer.by_ref(), 0),
2057            Bound::Included(value) => {
2058                C::TagEncoding::write_from_u32(writer.by_ref(), 1)?;
2059                T::write(writer, value)
2060            }
2061            Bound::Excluded(value) => {
2062                C::TagEncoding::write_from_u32(writer.by_ref(), 2)?;
2063                T::write(writer, value)
2064            }
2065        }
2066    }
2067}
2068
2069unsafe impl<'de, T, C: Config> SchemaRead<'de, C> for Bound<T>
2070where
2071    T: SchemaRead<'de, C>,
2072{
2073    type Dst = Bound<T::Dst>;
2074
2075    #[inline]
2076    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
2077        let disc = C::TagEncoding::try_into_u32(C::TagEncoding::get(reader.by_ref())?)?;
2078        match disc {
2079            0 => dst.write(Bound::Unbounded),
2080            1 => dst.write(Bound::Included(T::get(reader.by_ref())?)),
2081            2 => dst.write(Bound::Excluded(T::get(reader.by_ref())?)),
2082            _ => return Err(invalid_tag_encoding(disc as usize)),
2083        };
2084
2085        Ok(())
2086    }
2087}
2088
2089unsafe impl<Idx, C: Config> SchemaWrite<C> for Range<Idx>
2090where
2091    Idx: SchemaWrite<C>,
2092    Idx::Src: Sized,
2093{
2094    type Src = Range<Idx::Src>;
2095
2096    const TYPE_META: TypeMeta = const {
2097        match Idx::TYPE_META {
2098            TypeMeta::Static { size: idx_size, .. } => TypeMeta::Static {
2099                size: idx_size + idx_size,
2100                zero_copy: false,
2101            },
2102            TypeMeta::Dynamic => TypeMeta::Dynamic,
2103        }
2104    };
2105
2106    #[inline]
2107    #[allow(clippy::arithmetic_side_effects)]
2108    fn size_of(src: &Self::Src) -> WriteResult<usize> {
2109        Ok(Idx::size_of(&src.start)? + Idx::size_of(&src.end)?)
2110    }
2111
2112    #[inline]
2113    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
2114        match Self::TYPE_META {
2115            TypeMeta::Static { size, .. } => {
2116                // SAFETY: `Self::TYPE_META` specifies a static size, which is `static_size_of(Idx) * 2`.
2117                // reading `Idx` twice will consume `size` bytes, fully consuming the trusted window.
2118                let mut writer = unsafe { writer.as_trusted_for(size) }?;
2119                Idx::write(writer.by_ref(), &src.start)?;
2120                Idx::write(writer.by_ref(), &src.end)?;
2121                writer.finish()?;
2122            }
2123            TypeMeta::Dynamic => {
2124                Idx::write(writer.by_ref(), &src.start)?;
2125                Idx::write(writer.by_ref(), &src.end)?;
2126            }
2127        }
2128        Ok(())
2129    }
2130}
2131
2132unsafe impl<'de, Idx, C: ConfigCore> SchemaRead<'de, C> for Range<Idx>
2133where
2134    Idx: SchemaRead<'de, C>,
2135{
2136    type Dst = Range<Idx::Dst>;
2137
2138    const TYPE_META: TypeMeta = const {
2139        match Idx::TYPE_META {
2140            TypeMeta::Static { size: idx_size, .. } => TypeMeta::Static {
2141                size: idx_size + idx_size,
2142                zero_copy: false,
2143            },
2144            TypeMeta::Dynamic => TypeMeta::Dynamic,
2145        }
2146    };
2147
2148    #[inline]
2149    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
2150        match Self::TYPE_META {
2151            TypeMeta::Static { size, .. } => {
2152                // SAFETY: `Self::TYPE_META` specifies a static size, which is `static_size_of(Idx) * 2`.
2153                // reading `Idx` twice will consume `size` bytes, fully consuming the trusted window.
2154                let mut reader = unsafe { reader.as_trusted_for(size) }?;
2155                let start = Idx::get(reader.by_ref())?;
2156                let end = Idx::get(reader.by_ref())?;
2157                dst.write(Range { start, end });
2158            }
2159            TypeMeta::Dynamic => {
2160                let start = Idx::get(reader.by_ref())?;
2161                let end = Idx::get(reader.by_ref())?;
2162                dst.write(Range { start, end });
2163            }
2164        };
2165
2166        Ok(())
2167    }
2168}
2169
2170unsafe impl<Idx, C: ConfigCore> SchemaWrite<C> for RangeInclusive<Idx>
2171where
2172    Idx: SchemaWrite<C>,
2173    Idx::Src: Sized,
2174{
2175    type Src = RangeInclusive<Idx::Src>;
2176
2177    const TYPE_META: TypeMeta = const {
2178        match Idx::TYPE_META {
2179            TypeMeta::Static { size: idx_size, .. } => TypeMeta::Static {
2180                size: idx_size + idx_size,
2181                zero_copy: false,
2182            },
2183            TypeMeta::Dynamic => TypeMeta::Dynamic,
2184        }
2185    };
2186
2187    #[inline]
2188    #[allow(clippy::arithmetic_side_effects)]
2189    fn size_of(src: &Self::Src) -> WriteResult<usize> {
2190        if let TypeMeta::Static { size, .. } = Self::TYPE_META {
2191            return Ok(size);
2192        }
2193        Ok(Idx::size_of(src.start())? + Idx::size_of(src.end())?)
2194    }
2195
2196    #[inline]
2197    fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
2198        match Self::TYPE_META {
2199            TypeMeta::Static { size, .. } => {
2200                // SAFETY: `Self::TYPE_META` specifies a static size, which is `static_size_of(Idx) * 2`.
2201                // reading `Idx` twice will consume `size` bytes, fully consuming the trusted window.
2202                let mut writer = unsafe { writer.as_trusted_for(size) }?;
2203                Idx::write(writer.by_ref(), src.start())?;
2204                Idx::write(writer.by_ref(), src.end())?;
2205                writer.finish()?;
2206            }
2207            TypeMeta::Dynamic => {
2208                Idx::write(writer.by_ref(), src.start())?;
2209                Idx::write(writer.by_ref(), src.end())?;
2210            }
2211        }
2212        Ok(())
2213    }
2214}
2215
2216unsafe impl<'de, Idx, C: ConfigCore> SchemaRead<'de, C> for RangeInclusive<Idx>
2217where
2218    Idx: SchemaRead<'de, C>,
2219{
2220    type Dst = RangeInclusive<Idx::Dst>;
2221
2222    const TYPE_META: TypeMeta = const {
2223        match Idx::TYPE_META {
2224            TypeMeta::Static { size: idx_size, .. } => TypeMeta::Static {
2225                size: idx_size + idx_size,
2226                zero_copy: false,
2227            },
2228            TypeMeta::Dynamic => TypeMeta::Dynamic,
2229        }
2230    };
2231
2232    #[inline]
2233    fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
2234        match Self::TYPE_META {
2235            TypeMeta::Static { size, .. } => {
2236                // SAFETY: `Self::TYPE_META` specifies a static size, which is `static_size_of(Idx) * 2`.
2237                // reading `Idx` twice will consume `size` bytes, fully consuming the trusted window.
2238                let mut reader = unsafe { reader.as_trusted_for(size) }?;
2239                let start = Idx::get(reader.by_ref())?;
2240                let end = Idx::get(reader.by_ref())?;
2241                dst.write(RangeInclusive::new(start, end));
2242            }
2243            TypeMeta::Dynamic => {
2244                let start = Idx::get(reader.by_ref())?;
2245                let end = Idx::get(reader.by_ref())?;
2246                dst.write(RangeInclusive::new(start, end));
2247            }
2248        };
2249        Ok(())
2250    }
2251}
2252
2253#[cfg(feature = "alloc")]
2254unsafe impl<T: ?Sized, C: ConfigCore> SchemaWrite<C> for Cow<'_, T>
2255where
2256    T: ToOwned,
2257    T: SchemaWrite<C, Src = T>,
2258{
2259    type Src = Self;
2260
2261    #[inline]
2262    fn size_of(src: &Self::Src) -> WriteResult<usize> {
2263        T::size_of(src.as_ref())
2264    }
2265
2266    #[inline]
2267    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
2268        T::write(writer, src.as_ref())
2269    }
2270}
2271
2272#[cfg(feature = "alloc")]
2273unsafe impl<'de, T: ?Sized, C: ConfigCore> SchemaRead<'de, C> for Cow<'de, T>
2274where
2275    T: ToOwned,
2276    &'de T: SchemaRead<'de, C, Dst = &'de T>,
2277    T::Owned: SchemaRead<'de, C, Dst = T::Owned>,
2278{
2279    type Dst = Self;
2280
2281    #[inline]
2282    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
2283        let cow = if reader.supports_borrow(BorrowKind::Backing) {
2284            Cow::Borrowed(<&T as SchemaRead<C>>::get(reader)?)
2285        } else {
2286            Cow::Owned(<T::Owned as SchemaRead<C>>::get(reader)?)
2287        };
2288        dst.write(cow);
2289        Ok(())
2290    }
2291}
2292
2293#[cfg(feature = "alloc")]
2294unsafe impl<'de, T, C: ConfigCore> SchemaReadContext<'de, C, context::Len> for Cow<'de, [T]>
2295where
2296    [T]: ToOwned,
2297    &'de [T]: SchemaReadContext<'de, C, context::Len, Dst = &'de [T]>,
2298    <[T] as ToOwned>::Owned: SchemaReadContext<'de, C, context::Len, Dst = <[T] as ToOwned>::Owned>,
2299{
2300    type Dst = Self;
2301
2302    #[inline]
2303    fn read_with_context(
2304        ctx: context::Len,
2305        reader: impl Reader<'de>,
2306        dst: &mut MaybeUninit<Self::Dst>,
2307    ) -> ReadResult<()> {
2308        let cow = if reader.supports_borrow(BorrowKind::Backing) {
2309            Cow::Borrowed(<&[T]>::get_with_context(ctx, reader)?)
2310        } else {
2311            Cow::Owned(<<[T] as ToOwned>::Owned>::get_with_context(ctx, reader)?)
2312        };
2313        dst.write(cow);
2314        Ok(())
2315    }
2316}
2317
2318unsafe impl<C: ConfigCore, T> SchemaWrite<C> for Cell<T>
2319where
2320    T: SchemaWrite<C>,
2321    T::Src: Copy,
2322{
2323    type Src = Cell<T::Src>;
2324
2325    const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
2326
2327    #[inline]
2328    fn size_of(src: &Self::Src) -> WriteResult<usize> {
2329        T::size_of(&src.get())
2330    }
2331
2332    #[inline]
2333    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
2334        T::write(writer, &src.get())
2335    }
2336}
2337
2338unsafe impl<'de, C: ConfigCore, T> SchemaRead<'de, C> for Cell<T>
2339where
2340    T: SchemaRead<'de, C>,
2341{
2342    type Dst = Cell<T::Dst>;
2343
2344    const TYPE_META: TypeMeta = T::TYPE_META;
2345
2346    #[inline]
2347    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
2348        dst.write(T::get(reader).map(Self::Dst::new)?);
2349        Ok(())
2350    }
2351}
2352
2353unsafe impl<C: ConfigCore, T> SchemaWrite<C> for RefCell<T>
2354where
2355    T: SchemaWrite<C> + ?Sized,
2356{
2357    type Src = RefCell<T::Src>;
2358
2359    const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
2360
2361    #[inline]
2362    fn size_of(src: &Self::Src) -> WriteResult<usize> {
2363        let val = src
2364            .try_borrow()
2365            .map_err(|_| WriteError::Custom("RefCell already mutably borrowed"))?;
2366        T::size_of(&*val)
2367    }
2368
2369    #[inline]
2370    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
2371        let val = src
2372            .try_borrow()
2373            .map_err(|_| WriteError::Custom("RefCell already mutably borrowed"))?;
2374        T::write(writer, &*val)
2375    }
2376}
2377
2378unsafe impl<'de, C: ConfigCore, T> SchemaRead<'de, C> for RefCell<T>
2379where
2380    T: SchemaRead<'de, C> + ?Sized,
2381{
2382    type Dst = RefCell<T::Dst>;
2383
2384    const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
2385
2386    #[inline]
2387    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
2388        dst.write(T::get(reader).map(Self::Dst::new)?);
2389        Ok(())
2390    }
2391}
2392
2393#[cfg(feature = "std")]
2394unsafe impl<C: ConfigCore, T> SchemaWrite<C> for Mutex<T>
2395where
2396    T: SchemaWrite<C> + ?Sized,
2397{
2398    type Src = Mutex<T::Src>;
2399
2400    const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
2401
2402    #[inline]
2403    fn size_of(src: &Self::Src) -> WriteResult<usize> {
2404        let val = src
2405            .lock()
2406            .map_err(|_| WriteError::Custom("Mutex poisoned"))?;
2407        T::size_of(&*val)
2408    }
2409
2410    #[inline]
2411    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
2412        let val = src
2413            .lock()
2414            .map_err(|_| WriteError::Custom("Mutex poisoned"))?;
2415        T::write(writer, &*val)
2416    }
2417}
2418
2419#[cfg(feature = "std")]
2420unsafe impl<'de, C: ConfigCore, T> SchemaRead<'de, C> for Mutex<T>
2421where
2422    T: SchemaRead<'de, C> + ?Sized,
2423{
2424    type Dst = Mutex<T::Dst>;
2425
2426    const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
2427
2428    #[inline]
2429    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
2430        dst.write(T::get(reader).map(Self::Dst::new)?);
2431        Ok(())
2432    }
2433}
2434
2435#[cfg(feature = "std")]
2436unsafe impl<C: ConfigCore, T> SchemaWrite<C> for RwLock<T>
2437where
2438    T: SchemaWrite<C> + ?Sized,
2439{
2440    type Src = RwLock<T::Src>;
2441
2442    const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
2443
2444    #[inline]
2445    fn size_of(src: &Self::Src) -> WriteResult<usize> {
2446        let val = src
2447            .read()
2448            .map_err(|_| WriteError::Custom("RwLock poisoned"))?;
2449        T::size_of(&*val)
2450    }
2451
2452    #[inline]
2453    fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
2454        let val = src
2455            .read()
2456            .map_err(|_| WriteError::Custom("RwLock poisoned"))?;
2457        T::write(writer, &*val)
2458    }
2459}
2460
2461#[cfg(feature = "std")]
2462unsafe impl<'de, C: ConfigCore, T> SchemaRead<'de, C> for RwLock<T>
2463where
2464    T: SchemaRead<'de, C> + ?Sized,
2465{
2466    type Dst = RwLock<T::Dst>;
2467
2468    const TYPE_META: TypeMeta = T::TYPE_META.keep_zero_copy(false);
2469
2470    #[inline]
2471    fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
2472        dst.write(T::get(reader).map(Self::Dst::new)?);
2473        Ok(())
2474    }
2475}