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