Skip to main content

wincode/schema/
containers.rs

1//! This module provides specialized implementations of standard library collection types that
2//! provide control over the length encoding (see [`SeqLen`](crate::len::SeqLen)), as well
3//! as special case opt-in raw-copy overrides (see [`Pod`]).
4//!
5//! # Examples
6//! Raw byte vec with solana short vec length encoding:
7//!
8//! ```
9//! # #[cfg(all(feature = "solana-short-vec", feature = "alloc"))] {
10//! # use wincode::{containers::self, len::ShortU16Len};
11//! # use wincode_derive::SchemaWrite;
12//! # use serde::Serialize;
13//! # use solana_short_vec;
14//! #[derive(Serialize, SchemaWrite)]
15//! struct MyStruct {
16//!     #[serde(with = "solana_short_vec")]
17//!     #[wincode(with = "containers::Vec<_, ShortU16Len>")]
18//!     vec: Vec<u8>,
19//! }
20//!
21//! let my_struct = MyStruct {
22//!     vec: vec![1, 2, 3],
23//! };
24//! let wincode_bytes = wincode::serialize(&my_struct).unwrap();
25//! let bincode_bytes = bincode::serialize(&my_struct).unwrap();
26//! assert_eq!(wincode_bytes, bincode_bytes);
27//! # }
28//! ```
29//!
30//! Vector with struct elements and custom length encoding:
31//!
32//! ```
33//! # #[cfg(all(feature = "solana-short-vec", feature = "alloc", feature = "derive"))] {
34//! # use wincode_derive::SchemaWrite;
35//! # use wincode::{containers::self, len::ShortU16Len};
36//! # use serde::Serialize;
37//! # use solana_short_vec;
38//! #[derive(Serialize, SchemaWrite)]
39//! struct Point {
40//!     x: u64,
41//!     y: u64,
42//! }
43//!
44//! #[derive(Serialize, SchemaWrite)]
45//! struct MyStruct {
46//!     #[serde(with = "solana_short_vec")]
47//!     #[wincode(with = "containers::Vec<Point, ShortU16Len>")]
48//!     vec: Vec<Point>,
49//! }
50//!
51//! let my_struct = MyStruct {
52//!     vec: vec![Point { x: 1, y: 2 }, Point { x: 3, y: 4 }],
53//! };
54//! let wincode_bytes = wincode::serialize(&my_struct).unwrap();
55//! let bincode_bytes = bincode::serialize(&my_struct).unwrap();
56//! assert_eq!(wincode_bytes, bincode_bytes);
57//! # }
58//! ```
59use {
60    crate::{
61        error::{ReadResult, WriteResult},
62        io::{Reader, Writer},
63        schema::{SchemaRead, SchemaWrite},
64        TypeMeta, ZeroCopy,
65    },
66    core::{marker::PhantomData, mem::MaybeUninit, ptr},
67};
68#[cfg(feature = "alloc")]
69use {
70    crate::{
71        len::{BincodeLen, SeqLen},
72        schema::{size_of_elem_iter, size_of_elem_slice, write_elem_iter, write_elem_slice},
73    },
74    alloc::{boxed::Box as AllocBox, collections, rc::Rc as AllocRc, sync::Arc as AllocArc, vec},
75    core::mem::{self, ManuallyDrop},
76};
77
78/// A [`Vec`](std::vec::Vec) with a customizable length encoding.
79#[cfg(feature = "alloc")]
80pub struct Vec<T, Len = BincodeLen>(PhantomData<Len>, PhantomData<T>);
81
82/// A [`VecDeque`](std::collections::VecDeque) with a customizable length encoding.
83#[cfg(feature = "alloc")]
84pub struct VecDeque<T, Len = BincodeLen>(PhantomData<Len>, PhantomData<T>);
85
86/// A [`Box<[T]>`](std::boxed::Box) with a customizable length encoding.
87///
88/// # Examples
89///
90/// ```
91/// # #[cfg(all(feature = "alloc", feature = "derive", feature = "solana-short-vec"))] {
92/// # use wincode::{containers, len::ShortU16Len};
93/// # use wincode_derive::{SchemaWrite, SchemaRead};
94/// # use serde::{Serialize, Deserialize};
95/// # use std::array;
96/// #[derive(Serialize, SchemaWrite, Clone, Copy)]
97/// #[repr(transparent)]
98/// struct Address([u8; 32]);
99///
100/// #[derive(Serialize, SchemaWrite)]
101/// struct MyStruct {
102///     #[serde(with = "solana_short_vec")]
103///     #[wincode(with = "containers::Box<[Address], ShortU16Len>")]
104///     address: Box<[Address]>
105/// }
106///
107/// let my_struct = MyStruct {
108///     address: vec![Address(array::from_fn(|i| i as u8)); 10].into_boxed_slice(),
109/// };
110/// let wincode_bytes = wincode::serialize(&my_struct).unwrap();
111/// let bincode_bytes = bincode::serialize(&my_struct).unwrap();
112/// assert_eq!(wincode_bytes, bincode_bytes);
113/// # }
114/// ```
115#[cfg(feature = "alloc")]
116pub struct Box<T: ?Sized, Len = BincodeLen>(PhantomData<T>, PhantomData<Len>);
117
118#[cfg(feature = "alloc")]
119/// Like [`Box`], for [`Rc`].
120pub struct Rc<T: ?Sized, Len = BincodeLen>(PhantomData<T>, PhantomData<Len>);
121
122#[cfg(feature = "alloc")]
123/// Like [`Box`], for [`Arc`].
124pub struct Arc<T: ?Sized, Len = BincodeLen>(PhantomData<T>, PhantomData<Len>);
125
126#[cfg(feature = "bytes")]
127/// A [`bytes::Bytes`] with a customizable length encoding.
128pub struct Bytes<Len = BincodeLen>(PhantomData<Len>);
129
130#[cfg(feature = "bytes")]
131/// A [`bytes::BytesMut`] with a customizable length encoding.
132pub struct BytesMut<Len = BincodeLen>(PhantomData<Len>);
133
134/// Indicates that the type is an element of a sequence, composable with [`containers`](self).
135///
136/// Prefer [`Pod`] for types representable as raw bytes.
137#[deprecated(
138    since = "0.2.0",
139    note = "Elem is no longer needed for container usage. Use `T` directly instead."
140)]
141pub struct Elem<T>(PhantomData<T>);
142
143/// Indicates that the type is represented by raw bytes and does not have any invalid bit patterns.
144///
145/// By opting into `Pod`, you are telling wincode that it can serialize and deserialize a type
146/// with a single memcpy -- it wont pay attention to things like struct layout, endianness, or anything
147/// else that would require validity or bit pattern checks. This is a very strong claim to make,
148/// so be sure that your type adheres to those requirements.
149///
150/// Composable with sequence [`containers`](self) or compound types (structs, tuples) for
151/// an optimized read/write implementation.
152///
153///
154/// This can be useful outside of sequences as well, for example on newtype structs
155/// containing byte arrays with `#[repr(transparent)]`.
156///
157/// ---
158/// đź’ˇ **Note:** as of `wincode` `0.2.0`, `Pod` is no longer needed for types that wincode can determine
159/// are "Pod-safe".
160///
161/// This includes:
162/// - [`u8`]
163/// - [`[u8; N]`](prim@array)
164/// - structs comprised of the above, and;
165///     - annotated with `#[derive(SchemaWrite)]` or `#[derive(SchemaRead)]`, and;
166///     - annotated with `#[repr(transparent)]` or `#[repr(C)]`.
167///
168/// Similarly, using built-in std collections like `Vec<T>` or `Box<[T]>` where `T` is one of the
169/// above will also be automatically optimized.
170///
171/// You'll really only need to reach for [`Pod`] when dealing with foreign types for which you cannot
172/// derive `SchemaWrite` or `SchemaRead`. Or you're in a controlled scenario where you explicitly
173/// want to avoid endianness or layout checks.
174///
175/// # Safety
176///
177/// - The type must allow any bit pattern (e.g., no `bool`s, no `char`s, etc.)
178/// - If used on a compound type like a struct, all fields must be also be `Pod`, its
179///   layout must be guaranteed (via `#[repr(transparent)]` or `#[repr(C)]`), and the struct
180///   must not have any padding.
181/// - Must not contain references or pointers (includes types like `Vec` or `Box`).
182///     - Note, you may use `Pod` *inside* types like `Vec` or `Box`, e.g., `Vec<Pod<T>>` or `Box<[Pod<T>]>`,
183///       but specifying `Pod` on the outer type is invalid.
184///
185/// # Examples
186///
187/// A repr-transparent newtype struct containing a byte array where you cannot derive `SchemaWrite` or `SchemaRead`:
188/// ```
189/// # #[cfg(all(feature = "alloc", feature = "derive"))] {
190/// # use wincode::{containers::{self, Pod}};
191/// # use wincode_derive::{SchemaWrite, SchemaRead};
192/// # use serde::{Serialize, Deserialize};
193/// # use std::array;
194/// #[derive(Serialize, Deserialize, Clone, Copy)]
195/// #[repr(transparent)]
196/// struct Address([u8; 32]);
197///
198/// #[derive(Serialize, Deserialize, SchemaWrite, SchemaRead)]
199/// struct MyStruct {
200///     #[wincode(with = "Pod<_>")]
201///     address: Address
202/// }
203///
204/// let my_struct = MyStruct {
205///     address: Address(array::from_fn(|i| i as u8)),
206/// };
207/// let wincode_bytes = wincode::serialize(&my_struct).unwrap();
208/// let bincode_bytes = bincode::serialize(&my_struct).unwrap();
209/// assert_eq!(wincode_bytes, bincode_bytes);
210/// # }
211/// ```
212pub struct Pod<T: Copy + 'static>(PhantomData<T>);
213
214// SAFETY:
215// - By using `Pod`, user asserts that the type is zero-copy, given the contract of Pod:
216//   - The type's in‑memory representation is exactly its serialized bytes.
217//   - It can be safely initialized by memcpy (no validation, no endianness/layout work).
218//   - Does not contain references or pointers.
219unsafe impl<T> ZeroCopy for Pod<T> where T: Copy + 'static {}
220
221impl<T> SchemaWrite for Pod<T>
222where
223    T: Copy + 'static,
224{
225    type Src = T;
226
227    const TYPE_META: TypeMeta = TypeMeta::Static {
228        size: size_of::<T>(),
229        zero_copy: true,
230    };
231
232    #[inline]
233    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
234        Ok(size_of::<T>())
235    }
236
237    #[inline]
238    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
239        // SAFETY: `T` is plain ol' data.
240        unsafe { Ok(writer.write_t(src)?) }
241    }
242}
243
244impl<'de, T> SchemaRead<'de> for Pod<T>
245where
246    T: Copy + 'static,
247{
248    type Dst = T;
249
250    const TYPE_META: TypeMeta = TypeMeta::Static {
251        size: size_of::<T>(),
252        zero_copy: true,
253    };
254
255    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
256        // SAFETY: `T` is plain ol' data.
257        unsafe { Ok(reader.copy_into_t(dst)?) }
258    }
259}
260
261// Provide `SchemaWrite` implementation for `Elem<T>` for backwards compatibility.
262//
263// Container impls use blanket implementations over `T` where `T` is `SchemaWrite`,
264// so this preserves existing behavior, such that `Elem<T>` behaves exactly like `T`.
265#[allow(deprecated)]
266impl<T> SchemaWrite for Elem<T>
267where
268    T: SchemaWrite,
269{
270    type Src = T::Src;
271
272    const TYPE_META: TypeMeta = T::TYPE_META;
273
274    #[inline]
275    fn size_of(src: &Self::Src) -> WriteResult<usize> {
276        T::size_of(src)
277    }
278
279    #[inline]
280    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
281        T::write(writer, src)
282    }
283}
284
285// Provide `SchemaRead` implementation for `Elem<T>` for backwards compatibility.
286//
287// Container impls use blanket implementations over `T` where `T` is `SchemaRead`,
288// so this preserves existing behavior, such that `Elem<T>` behaves exactly like `T`.
289#[allow(deprecated)]
290impl<'de, T> SchemaRead<'de> for Elem<T>
291where
292    T: SchemaRead<'de>,
293{
294    type Dst = T::Dst;
295
296    const TYPE_META: TypeMeta = T::TYPE_META;
297
298    #[inline]
299    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
300        T::read(reader, dst)
301    }
302}
303
304#[cfg(feature = "alloc")]
305impl<T, Len> SchemaWrite for Vec<T, Len>
306where
307    Len: SeqLen,
308    T: SchemaWrite,
309    T::Src: Sized,
310{
311    type Src = vec::Vec<T::Src>;
312
313    #[inline(always)]
314    fn size_of(src: &Self::Src) -> WriteResult<usize> {
315        size_of_elem_slice::<T, Len>(src)
316    }
317
318    #[inline(always)]
319    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
320        write_elem_slice::<T, Len>(writer, src)
321    }
322}
323
324#[cfg(feature = "alloc")]
325impl<'de, T, Len> SchemaRead<'de> for Vec<T, Len>
326where
327    Len: SeqLen,
328    T: SchemaRead<'de>,
329{
330    type Dst = vec::Vec<T::Dst>;
331
332    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
333        let len = Len::read::<T::Dst>(reader)?;
334        let mut vec: vec::Vec<T::Dst> = vec::Vec::with_capacity(len);
335
336        match T::TYPE_META {
337            TypeMeta::Static {
338                zero_copy: true, ..
339            } => {
340                let spare_capacity = vec.spare_capacity_mut();
341                // SAFETY: T::Dst is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
342                unsafe { reader.copy_into_slice_t(spare_capacity)? };
343                // SAFETY: `copy_into_slice_t` fills the entire spare capacity or errors.
344                unsafe { vec.set_len(len) };
345            }
346            TypeMeta::Static {
347                size,
348                zero_copy: false,
349            } => {
350                let mut ptr = vec.as_mut_ptr().cast::<MaybeUninit<T::Dst>>();
351                #[allow(clippy::arithmetic_side_effects)]
352                // SAFETY: `T::TYPE_META` specifies a static size, so `len` reads of `T::Dst`
353                // will consume `size * len` bytes, fully consuming the trusted window.
354                let mut reader = unsafe { reader.as_trusted_for(size * len) }?;
355                for i in 0..len {
356                    T::read(&mut reader, unsafe { &mut *ptr })?;
357                    unsafe {
358                        ptr = ptr.add(1);
359                        #[allow(clippy::arithmetic_side_effects)]
360                        // i <= len
361                        vec.set_len(i + 1);
362                    }
363                }
364            }
365            TypeMeta::Dynamic => {
366                let mut ptr = vec.as_mut_ptr().cast::<MaybeUninit<T::Dst>>();
367                for i in 0..len {
368                    T::read(reader, unsafe { &mut *ptr })?;
369                    unsafe {
370                        ptr = ptr.add(1);
371                        #[allow(clippy::arithmetic_side_effects)]
372                        // i <= len
373                        vec.set_len(i + 1);
374                    }
375                }
376            }
377        }
378
379        dst.write(vec);
380        Ok(())
381    }
382}
383
384pub(crate) struct SliceDropGuard<T> {
385    ptr: *mut MaybeUninit<T>,
386    initialized_len: usize,
387}
388
389impl<T> SliceDropGuard<T> {
390    pub(crate) fn new(ptr: *mut MaybeUninit<T>) -> Self {
391        Self {
392            ptr,
393            initialized_len: 0,
394        }
395    }
396
397    #[inline(always)]
398    #[allow(clippy::arithmetic_side_effects)]
399    pub(crate) fn inc_len(&mut self) {
400        self.initialized_len += 1;
401    }
402}
403
404impl<T> Drop for SliceDropGuard<T> {
405    #[inline(always)]
406    fn drop(&mut self) {
407        unsafe {
408            ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
409                self.ptr.cast::<T>(),
410                self.initialized_len,
411            ));
412        }
413    }
414}
415
416macro_rules! impl_heap_slice {
417    ($container:ident => $target:ident) => {
418        #[cfg(feature = "alloc")]
419        impl<T, Len> SchemaWrite for $container<[T], Len>
420        where
421            Len: SeqLen,
422            T: SchemaWrite,
423            T::Src: Sized,
424        {
425            type Src = $target<[T::Src]>;
426
427            #[inline(always)]
428            fn size_of(src: &Self::Src) -> WriteResult<usize> {
429                size_of_elem_slice::<T, Len>(src)
430            }
431
432            #[inline(always)]
433            fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
434                write_elem_slice::<T, Len>(writer, src)
435            }
436        }
437
438        #[cfg(feature = "alloc")]
439        impl<'de, T, Len> SchemaRead<'de> for $container<[T], Len>
440        where
441            Len: SeqLen,
442            T: SchemaRead<'de>,
443        {
444            type Dst = $target<[T::Dst]>;
445
446            #[inline(always)]
447            fn read(
448                reader: &mut impl Reader<'de>,
449                dst: &mut MaybeUninit<Self::Dst>,
450            ) -> ReadResult<()> {
451                /// Drop guard for `TypeMeta::Static { zero_copy: true }` types.
452                ///
453                /// In this case we do not need to drop items individually, as
454                /// the container will be initialized by a single memcpy.
455                struct DropGuardRawCopy<T>(*mut [MaybeUninit<T>]);
456                impl<T> Drop for DropGuardRawCopy<T> {
457                    #[inline]
458                    fn drop(&mut self) {
459                        // SAFETY:
460                        // - `self.0` is a valid pointer to the container created
461                        //   by `$target::into_raw`.
462                        // - `drop` is only called in this drop guard, and the drop guard
463                        //   is forgotten if reading succeeds.
464                        let container = unsafe { $target::from_raw(self.0) };
465                        drop(container);
466                    }
467                }
468
469                /// Drop guard for `TypeMeta::Static { zero_copy: false } | TypeMeta::Dynamic` types.
470                ///
471                /// In this case we need to drop items individually, as
472                /// the container will be initialized by a series of reads.
473                struct DropGuardElemCopy<T> {
474                    inner: ManuallyDrop<SliceDropGuard<T>>,
475                    fat: *mut [MaybeUninit<T>],
476                }
477
478                impl<T> DropGuardElemCopy<T> {
479                    #[inline(always)]
480                    fn new(fat: *mut [MaybeUninit<T>], raw: *mut MaybeUninit<T>) -> Self {
481                        Self {
482                            inner: ManuallyDrop::new(SliceDropGuard::new(raw)),
483                            // We need to store the fat pointer to deallocate the container.
484                            fat,
485                        }
486                    }
487                }
488
489                impl<T> Drop for DropGuardElemCopy<T> {
490                    #[inline]
491                    fn drop(&mut self) {
492                        // SAFETY: `ManuallyDrop::drop` is only called in this drop guard.
493                        unsafe {
494                            // Drop the initialized elements first.
495                            ManuallyDrop::drop(&mut self.inner);
496                        }
497
498                        // SAFETY:
499                        // - `self.fat` is a valid pointer to the container created with `$target::into_raw`.
500                        // - `drop` is only called in this drop guard, and the drop guard is forgotten if read succeeds.
501                        let container = unsafe { $target::from_raw(self.fat) };
502                        drop(container);
503                    }
504                }
505
506                let len = Len::read::<T::Dst>(reader)?;
507                let mem = $target::<[T::Dst]>::new_uninit_slice(len);
508                let fat = $target::into_raw(mem) as *mut [MaybeUninit<T::Dst>];
509
510                match T::TYPE_META {
511                    TypeMeta::Static {
512                        zero_copy: true, ..
513                    } => {
514                        let guard = DropGuardRawCopy(fat);
515                        // SAFETY: `fat` is a valid pointer to the container created with `$target::into_raw`.
516                        let dst = unsafe { &mut *fat };
517                        // SAFETY: T is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
518                        unsafe { reader.copy_into_slice_t(dst)? };
519                        mem::forget(guard);
520                    }
521                    TypeMeta::Static {
522                        size,
523                        zero_copy: false,
524                    } => {
525                        // SAFETY: `fat` is a valid pointer to the container created with `$target::into_raw`.
526                        let raw_base = unsafe { (*fat).as_mut_ptr() };
527                        let mut guard: DropGuardElemCopy<T::Dst> =
528                            DropGuardElemCopy::new(fat, raw_base);
529
530                        // SAFETY: `T::TYPE_META` specifies a static size, so `len` reads of `T::Dst`
531                        // will consume `size * len` bytes, fully consuming the trusted window.
532                        #[allow(clippy::arithmetic_side_effects)]
533                        let reader = &mut unsafe { reader.as_trusted_for(size * len) }?;
534                        for i in 0..len {
535                            // SAFETY:
536                            // - `raw_base` is a valid pointer to the container created with `$target::into_raw`.
537                            // - The container is initialized with capacity for `len` elements, and `i` is guaranteed to be
538                            //   less than `len`.
539                            let slot = unsafe { &mut *raw_base.add(i) };
540                            T::read(reader, slot)?;
541                            guard.inner.inc_len();
542                        }
543
544                        mem::forget(guard);
545                    }
546                    TypeMeta::Dynamic => {
547                        // SAFETY: `fat` is a valid pointer to the container created with `$target::into_raw`.
548                        let raw_base = unsafe { (*fat).as_mut_ptr() };
549                        let mut guard: DropGuardElemCopy<T::Dst> =
550                            DropGuardElemCopy::new(fat, raw_base);
551
552                        for i in 0..len {
553                            // SAFETY:
554                            // - `raw_base` is a valid pointer to the container created with `$target::into_raw`.
555                            // - The container is initialized with capacity for `len` elements, and `i` is guaranteed to be
556                            //   less than `len`.
557                            let slot = unsafe { &mut *raw_base.add(i) };
558                            T::read(reader, slot)?;
559                            guard.inner.inc_len();
560                        }
561
562                        mem::forget(guard);
563                    }
564                }
565
566                // SAFETY:
567                // - `fat` is a valid pointer to the container created with `$target::into_raw`.
568                // - the pointer memory is only deallocated in the drop guard, and the drop guard
569                //   is forgotten if reading succeeds.
570                let container = unsafe { $target::from_raw(fat) };
571                // SAFETY: `container` is fully initialized if read succeeds.
572                let container = unsafe { container.assume_init() };
573
574                dst.write(container);
575                Ok(())
576            }
577        }
578    };
579}
580
581impl_heap_slice!(Box => AllocBox);
582impl_heap_slice!(Rc => AllocRc);
583impl_heap_slice!(Arc => AllocArc);
584
585#[cfg(feature = "alloc")]
586impl<T, Len> SchemaWrite for VecDeque<T, Len>
587where
588    Len: SeqLen,
589    T: SchemaWrite,
590    T::Src: Sized,
591{
592    type Src = collections::VecDeque<T::Src>;
593
594    #[inline(always)]
595    fn size_of(value: &Self::Src) -> WriteResult<usize> {
596        size_of_elem_iter::<T, Len>(value.iter())
597    }
598
599    #[inline(always)]
600    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
601        if let TypeMeta::Static {
602            size,
603            zero_copy: true,
604        } = T::TYPE_META
605        {
606            #[allow(clippy::arithmetic_side_effects)]
607            let needed = Len::write_bytes_needed(src.len())? + src.len() * size;
608            // SAFETY: `needed` is the size of the encoded length plus the size of the items.
609            // `Len::write` and `len` writes of `T::Src` will write `needed` bytes,
610            // fully initializing the trusted window.
611            let writer = &mut unsafe { writer.as_trusted_for(needed) }?;
612
613            Len::write(writer, src.len())?;
614            let (front, back) = src.as_slices();
615            // SAFETY:
616            // - `T` is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
617            // - `front` and `back` are valid non-overlapping slices.
618            unsafe {
619                writer.write_slice_t(front)?;
620                writer.write_slice_t(back)?;
621            }
622
623            writer.finish()?;
624
625            return Ok(());
626        }
627
628        write_elem_iter::<T, Len>(writer, src.iter())
629    }
630}
631
632#[cfg(feature = "alloc")]
633impl<'de, T, Len> SchemaRead<'de> for VecDeque<T, Len>
634where
635    Len: SeqLen,
636    T: SchemaRead<'de>,
637{
638    type Dst = collections::VecDeque<T::Dst>;
639
640    #[inline(always)]
641    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
642        // Leverage the contiguous read optimization of `Vec`.
643        // From<Vec<T>> for VecDeque<T> is basically free.
644        let vec = <Vec<T, Len>>::get(reader)?;
645        dst.write(vec.into());
646        Ok(())
647    }
648}
649
650#[cfg(feature = "alloc")]
651/// A [`BinaryHeap`](alloc::collections::BinaryHeap) with a customizable length encoding.
652pub struct BinaryHeap<T, Len = BincodeLen>(PhantomData<Len>, PhantomData<T>);
653
654#[cfg(feature = "alloc")]
655impl<T, Len> SchemaWrite for BinaryHeap<T, Len>
656where
657    Len: SeqLen,
658    T: SchemaWrite,
659    T::Src: Sized,
660{
661    type Src = collections::BinaryHeap<T::Src>;
662
663    #[inline(always)]
664    fn size_of(src: &Self::Src) -> WriteResult<usize> {
665        size_of_elem_slice::<T, Len>(src.as_slice())
666    }
667
668    #[inline(always)]
669    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
670        write_elem_slice::<T, Len>(writer, src.as_slice())
671    }
672}
673
674#[cfg(feature = "alloc")]
675impl<'de, T, Len> SchemaRead<'de> for BinaryHeap<T, Len>
676where
677    Len: SeqLen,
678    T: SchemaRead<'de>,
679    T::Dst: Ord,
680{
681    type Dst = collections::BinaryHeap<T::Dst>;
682
683    #[inline(always)]
684    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
685        let vec = <Vec<T, Len>>::get(reader)?;
686        // Leverage the vec impl.
687        dst.write(collections::BinaryHeap::from(vec));
688        Ok(())
689    }
690}
691
692#[cfg(feature = "bytes")]
693impl<Len> SchemaWrite for Bytes<Len>
694where
695    Len: SeqLen,
696{
697    type Src = bytes::Bytes;
698
699    #[inline]
700    #[allow(clippy::arithmetic_side_effects)]
701    fn size_of(src: &Self::Src) -> WriteResult<usize> {
702        Ok(Len::write_bytes_needed(src.len())? + src.len())
703    }
704
705    #[inline]
706    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
707        Len::write(writer, src.len())?;
708        writer.write(src.as_ref())?;
709        Ok(())
710    }
711}
712
713#[cfg(feature = "bytes")]
714impl<'de, Len> SchemaRead<'de> for Bytes<Len>
715where
716    Len: SeqLen,
717{
718    type Dst = bytes::Bytes;
719
720    #[inline]
721    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
722        let len = Len::read::<u8>(reader)?;
723        let bytes = reader.fill_exact(len)?.to_vec();
724        unsafe { reader.consume_unchecked(len) };
725        dst.write(bytes::Bytes::from(bytes));
726        Ok(())
727    }
728}
729
730#[cfg(feature = "bytes")]
731impl<Len> SchemaWrite for BytesMut<Len>
732where
733    Len: SeqLen,
734{
735    type Src = bytes::BytesMut;
736
737    #[inline]
738    #[allow(clippy::arithmetic_side_effects)]
739    fn size_of(src: &Self::Src) -> WriteResult<usize> {
740        Ok(Len::write_bytes_needed(src.len())? + src.len())
741    }
742
743    #[inline]
744    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
745        Len::write(writer, src.len())?;
746        writer.write(src.as_ref())?;
747        Ok(())
748    }
749}
750
751#[cfg(feature = "bytes")]
752impl<'de, Len> SchemaRead<'de> for BytesMut<Len>
753where
754    Len: SeqLen,
755{
756    type Dst = bytes::BytesMut;
757
758    #[inline]
759    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
760        let len = Len::read::<u8>(reader)?;
761        let bytes = reader.fill_exact(len)?.to_vec();
762        unsafe { reader.consume_unchecked(len) };
763        dst.write(bytes::BytesMut::from(bytes.as_slice()));
764        Ok(())
765    }
766}