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/// Indicates that the type is an element of a sequence, composable with [`containers`](self).
127///
128/// Prefer [`Pod`] for types representable as raw bytes.
129#[deprecated(
130    since = "0.2.0",
131    note = "Elem is no longer needed for container usage. Use `T` directly instead."
132)]
133pub struct Elem<T>(PhantomData<T>);
134
135/// Indicates that the type is represented by raw bytes and does not have any invalid bit patterns.
136///
137/// By opting into `Pod`, you are telling wincode that it can serialize and deserialize a type
138/// with a single memcpy -- it wont pay attention to things like struct layout, endianness, or anything
139/// else that would require validity or bit pattern checks. This is a very strong claim to make,
140/// so be sure that your type adheres to those requirements.
141///
142/// Composable with sequence [`containers`](self) or compound types (structs, tuples) for
143/// an optimized read/write implementation.
144///
145///
146/// This can be useful outside of sequences as well, for example on newtype structs
147/// containing byte arrays with `#[repr(transparent)]`.
148///
149/// ---
150/// đź’ˇ **Note:** as of `wincode` `0.2.0`, `Pod` is no longer needed for types that wincode can determine
151/// are "Pod-safe".
152///
153/// This includes:
154/// - [`u8`]
155/// - [`[u8; N]`](prim@array)
156/// - structs comprised of the above, and;
157///     - annotated with `#[derive(SchemaWrite)]` or `#[derive(SchemaRead)]`, and;
158///     - annotated with `#[repr(transparent)]` or `#[repr(C)]`.
159///
160/// Similarly, using built-in std collections like `Vec<T>` or `Box<[T]>` where `T` is one of the
161/// above will also be automatically optimized.
162///
163/// You'll really only need to reach for [`Pod`] when dealing with foreign types for which you cannot
164/// derive `SchemaWrite` or `SchemaRead`. Or you're in a controlled scenario where you explicitly
165/// want to avoid endianness or layout checks.
166///
167/// # Safety
168///
169/// - The type must allow any bit pattern (e.g., no `bool`s, no `char`s, etc.)
170/// - If used on a compound type like a struct, all fields must be also be `Pod`, its
171///   layout must be guaranteed (via `#[repr(transparent)]` or `#[repr(C)]`), and the struct
172///   must not have any padding.
173/// - Must not contain references or pointers (includes types like `Vec` or `Box`).
174///     - Note, you may use `Pod` *inside* types like `Vec` or `Box`, e.g., `Vec<Pod<T>>` or `Box<[Pod<T>]>`,
175///       but specifying `Pod` on the outer type is invalid.
176///
177/// # Examples
178///
179/// A repr-transparent newtype struct containing a byte array where you cannot derive `SchemaWrite` or `SchemaRead`:
180/// ```
181/// # #[cfg(all(feature = "alloc", feature = "derive"))] {
182/// # use wincode::{containers::{self, Pod}};
183/// # use wincode_derive::{SchemaWrite, SchemaRead};
184/// # use serde::{Serialize, Deserialize};
185/// # use std::array;
186/// #[derive(Serialize, Deserialize, Clone, Copy)]
187/// #[repr(transparent)]
188/// struct Address([u8; 32]);
189///
190/// #[derive(Serialize, Deserialize, SchemaWrite, SchemaRead)]
191/// struct MyStruct {
192///     #[wincode(with = "Pod<_>")]
193///     address: Address
194/// }
195///
196/// let my_struct = MyStruct {
197///     address: Address(array::from_fn(|i| i as u8)),
198/// };
199/// let wincode_bytes = wincode::serialize(&my_struct).unwrap();
200/// let bincode_bytes = bincode::serialize(&my_struct).unwrap();
201/// assert_eq!(wincode_bytes, bincode_bytes);
202/// # }
203/// ```
204pub struct Pod<T: Copy + 'static>(PhantomData<T>);
205
206// SAFETY:
207// - By using `Pod`, user asserts that the type is zero-copy, given the contract of Pod:
208//   - The type's in‑memory representation is exactly its serialized bytes.
209//   - It can be safely initialized by memcpy (no validation, no endianness/layout work).
210//   - Does not contain references or pointers.
211unsafe impl<T> ZeroCopy for Pod<T> where T: Copy + 'static {}
212
213impl<T> SchemaWrite for Pod<T>
214where
215    T: Copy + 'static,
216{
217    type Src = T;
218
219    const TYPE_META: TypeMeta = TypeMeta::Static {
220        size: size_of::<T>(),
221        zero_copy: true,
222    };
223
224    #[inline]
225    fn size_of(_src: &Self::Src) -> WriteResult<usize> {
226        Ok(size_of::<T>())
227    }
228
229    #[inline]
230    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
231        // SAFETY: `T` is plain ol' data.
232        unsafe { Ok(writer.write_t(src)?) }
233    }
234}
235
236impl<'de, T> SchemaRead<'de> for Pod<T>
237where
238    T: Copy + 'static,
239{
240    type Dst = T;
241
242    const TYPE_META: TypeMeta = TypeMeta::Static {
243        size: size_of::<T>(),
244        zero_copy: true,
245    };
246
247    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
248        // SAFETY: `T` is plain ol' data.
249        unsafe { Ok(reader.copy_into_t(dst)?) }
250    }
251}
252
253// Provide `SchemaWrite` implementation for `Elem<T>` for backwards compatibility.
254//
255// Container impls use blanket implementations over `T` where `T` is `SchemaWrite`,
256// so this preserves existing behavior, such that `Elem<T>` behaves exactly like `T`.
257#[allow(deprecated)]
258impl<T> SchemaWrite for Elem<T>
259where
260    T: SchemaWrite,
261{
262    type Src = T::Src;
263
264    const TYPE_META: TypeMeta = T::TYPE_META;
265
266    #[inline]
267    fn size_of(src: &Self::Src) -> WriteResult<usize> {
268        T::size_of(src)
269    }
270
271    #[inline]
272    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
273        T::write(writer, src)
274    }
275}
276
277// Provide `SchemaRead` implementation for `Elem<T>` for backwards compatibility.
278//
279// Container impls use blanket implementations over `T` where `T` is `SchemaRead`,
280// so this preserves existing behavior, such that `Elem<T>` behaves exactly like `T`.
281#[allow(deprecated)]
282impl<'de, T> SchemaRead<'de> for Elem<T>
283where
284    T: SchemaRead<'de>,
285{
286    type Dst = T::Dst;
287
288    const TYPE_META: TypeMeta = T::TYPE_META;
289
290    #[inline]
291    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
292        T::read(reader, dst)
293    }
294}
295
296#[cfg(feature = "alloc")]
297impl<T, Len> SchemaWrite for Vec<T, Len>
298where
299    Len: SeqLen,
300    T: SchemaWrite,
301    T::Src: Sized,
302{
303    type Src = vec::Vec<T::Src>;
304
305    #[inline(always)]
306    fn size_of(src: &Self::Src) -> WriteResult<usize> {
307        size_of_elem_slice::<T, Len>(src)
308    }
309
310    #[inline(always)]
311    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
312        write_elem_slice::<T, Len>(writer, src)
313    }
314}
315
316#[cfg(feature = "alloc")]
317impl<'de, T, Len> SchemaRead<'de> for Vec<T, Len>
318where
319    Len: SeqLen,
320    T: SchemaRead<'de>,
321{
322    type Dst = vec::Vec<T::Dst>;
323
324    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
325        let len = Len::read::<T::Dst>(reader)?;
326        let mut vec: vec::Vec<T::Dst> = vec::Vec::with_capacity(len);
327
328        match T::TYPE_META {
329            TypeMeta::Static {
330                zero_copy: true, ..
331            } => {
332                let spare_capacity = vec.spare_capacity_mut();
333                // SAFETY: T::Dst is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
334                unsafe { reader.copy_into_slice_t(spare_capacity)? };
335                // SAFETY: `copy_into_slice_t` fills the entire spare capacity or errors.
336                unsafe { vec.set_len(len) };
337            }
338            TypeMeta::Static {
339                size,
340                zero_copy: false,
341            } => {
342                let mut ptr = vec.as_mut_ptr().cast::<MaybeUninit<T::Dst>>();
343                #[allow(clippy::arithmetic_side_effects)]
344                // SAFETY: `T::TYPE_META` specifies a static size, so `len` reads of `T::Dst`
345                // will consume `size * len` bytes, fully consuming the trusted window.
346                let mut reader = unsafe { reader.as_trusted_for(size * len) }?;
347                for i in 0..len {
348                    T::read(&mut reader, unsafe { &mut *ptr })?;
349                    unsafe {
350                        ptr = ptr.add(1);
351                        #[allow(clippy::arithmetic_side_effects)]
352                        // i <= len
353                        vec.set_len(i + 1);
354                    }
355                }
356            }
357            TypeMeta::Dynamic => {
358                let mut ptr = vec.as_mut_ptr().cast::<MaybeUninit<T::Dst>>();
359                for i in 0..len {
360                    T::read(reader, unsafe { &mut *ptr })?;
361                    unsafe {
362                        ptr = ptr.add(1);
363                        #[allow(clippy::arithmetic_side_effects)]
364                        // i <= len
365                        vec.set_len(i + 1);
366                    }
367                }
368            }
369        }
370
371        dst.write(vec);
372        Ok(())
373    }
374}
375
376pub(crate) struct SliceDropGuard<T> {
377    ptr: *mut MaybeUninit<T>,
378    initialized_len: usize,
379}
380
381impl<T> SliceDropGuard<T> {
382    pub(crate) fn new(ptr: *mut MaybeUninit<T>) -> Self {
383        Self {
384            ptr,
385            initialized_len: 0,
386        }
387    }
388
389    #[inline(always)]
390    #[allow(clippy::arithmetic_side_effects)]
391    pub(crate) fn inc_len(&mut self) {
392        self.initialized_len += 1;
393    }
394}
395
396impl<T> Drop for SliceDropGuard<T> {
397    #[inline(always)]
398    fn drop(&mut self) {
399        unsafe {
400            ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
401                self.ptr.cast::<T>(),
402                self.initialized_len,
403            ));
404        }
405    }
406}
407
408macro_rules! impl_heap_slice {
409    ($container:ident => $target:ident) => {
410        #[cfg(feature = "alloc")]
411        impl<T, Len> SchemaWrite for $container<[T], Len>
412        where
413            Len: SeqLen,
414            T: SchemaWrite,
415            T::Src: Sized,
416        {
417            type Src = $target<[T::Src]>;
418
419            #[inline(always)]
420            fn size_of(src: &Self::Src) -> WriteResult<usize> {
421                size_of_elem_slice::<T, Len>(src)
422            }
423
424            #[inline(always)]
425            fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
426                write_elem_slice::<T, Len>(writer, src)
427            }
428        }
429
430        #[cfg(feature = "alloc")]
431        impl<'de, T, Len> SchemaRead<'de> for $container<[T], Len>
432        where
433            Len: SeqLen,
434            T: SchemaRead<'de>,
435        {
436            type Dst = $target<[T::Dst]>;
437
438            #[inline(always)]
439            fn read(
440                reader: &mut impl Reader<'de>,
441                dst: &mut MaybeUninit<Self::Dst>,
442            ) -> ReadResult<()> {
443                /// Drop guard for `TypeMeta::Static { zero_copy: true }` types.
444                ///
445                /// In this case we do not need to drop items individually, as
446                /// the container will be initialized by a single memcpy.
447                struct DropGuardRawCopy<T>(*mut [MaybeUninit<T>]);
448                impl<T> Drop for DropGuardRawCopy<T> {
449                    #[inline]
450                    fn drop(&mut self) {
451                        // SAFETY:
452                        // - `self.0` is a valid pointer to the container created
453                        //   by `$target::into_raw`.
454                        // - `drop` is only called in this drop guard, and the drop guard
455                        //   is forgotten if reading succeeds.
456                        let container = unsafe { $target::from_raw(self.0) };
457                        drop(container);
458                    }
459                }
460
461                /// Drop guard for `TypeMeta::Static { zero_copy: false } | TypeMeta::Dynamic` types.
462                ///
463                /// In this case we need to drop items individually, as
464                /// the container will be initialized by a series of reads.
465                struct DropGuardElemCopy<T> {
466                    inner: ManuallyDrop<SliceDropGuard<T>>,
467                    fat: *mut [MaybeUninit<T>],
468                }
469
470                impl<T> DropGuardElemCopy<T> {
471                    #[inline(always)]
472                    fn new(fat: *mut [MaybeUninit<T>], raw: *mut MaybeUninit<T>) -> Self {
473                        Self {
474                            inner: ManuallyDrop::new(SliceDropGuard::new(raw)),
475                            // We need to store the fat pointer to deallocate the container.
476                            fat,
477                        }
478                    }
479                }
480
481                impl<T> Drop for DropGuardElemCopy<T> {
482                    #[inline]
483                    fn drop(&mut self) {
484                        // SAFETY: `ManuallyDrop::drop` is only called in this drop guard.
485                        unsafe {
486                            // Drop the initialized elements first.
487                            ManuallyDrop::drop(&mut self.inner);
488                        }
489
490                        // SAFETY:
491                        // - `self.fat` is a valid pointer to the container created with `$target::into_raw`.
492                        // - `drop` is only called in this drop guard, and the drop guard is forgotten if read succeeds.
493                        let container = unsafe { $target::from_raw(self.fat) };
494                        drop(container);
495                    }
496                }
497
498                let len = Len::read::<T::Dst>(reader)?;
499                let mem = $target::<[T::Dst]>::new_uninit_slice(len);
500                let fat = $target::into_raw(mem) as *mut [MaybeUninit<T::Dst>];
501
502                match T::TYPE_META {
503                    TypeMeta::Static {
504                        zero_copy: true, ..
505                    } => {
506                        let guard = DropGuardRawCopy(fat);
507                        // SAFETY: `fat` is a valid pointer to the container created with `$target::into_raw`.
508                        let dst = unsafe { &mut *fat };
509                        // SAFETY: T is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
510                        unsafe { reader.copy_into_slice_t(dst)? };
511                        mem::forget(guard);
512                    }
513                    TypeMeta::Static {
514                        size,
515                        zero_copy: false,
516                    } => {
517                        // SAFETY: `fat` is a valid pointer to the container created with `$target::into_raw`.
518                        let raw_base = unsafe { (*fat).as_mut_ptr() };
519                        let mut guard: DropGuardElemCopy<T::Dst> =
520                            DropGuardElemCopy::new(fat, raw_base);
521
522                        // SAFETY: `T::TYPE_META` specifies a static size, so `len` reads of `T::Dst`
523                        // will consume `size * len` bytes, fully consuming the trusted window.
524                        #[allow(clippy::arithmetic_side_effects)]
525                        let reader = &mut unsafe { reader.as_trusted_for(size * len) }?;
526                        for i in 0..len {
527                            // SAFETY:
528                            // - `raw_base` is a valid pointer to the container created with `$target::into_raw`.
529                            // - The container is initialized with capacity for `len` elements, and `i` is guaranteed to be
530                            //   less than `len`.
531                            let slot = unsafe { &mut *raw_base.add(i) };
532                            T::read(reader, slot)?;
533                            guard.inner.inc_len();
534                        }
535
536                        mem::forget(guard);
537                    }
538                    TypeMeta::Dynamic => {
539                        // SAFETY: `fat` is a valid pointer to the container created with `$target::into_raw`.
540                        let raw_base = unsafe { (*fat).as_mut_ptr() };
541                        let mut guard: DropGuardElemCopy<T::Dst> =
542                            DropGuardElemCopy::new(fat, raw_base);
543
544                        for i in 0..len {
545                            // SAFETY:
546                            // - `raw_base` is a valid pointer to the container created with `$target::into_raw`.
547                            // - The container is initialized with capacity for `len` elements, and `i` is guaranteed to be
548                            //   less than `len`.
549                            let slot = unsafe { &mut *raw_base.add(i) };
550                            T::read(reader, slot)?;
551                            guard.inner.inc_len();
552                        }
553
554                        mem::forget(guard);
555                    }
556                }
557
558                // SAFETY:
559                // - `fat` is a valid pointer to the container created with `$target::into_raw`.
560                // - the pointer memory is only deallocated in the drop guard, and the drop guard
561                //   is forgotten if reading succeeds.
562                let container = unsafe { $target::from_raw(fat) };
563                // SAFETY: `container` is fully initialized if read succeeds.
564                let container = unsafe { container.assume_init() };
565
566                dst.write(container);
567                Ok(())
568            }
569        }
570    };
571}
572
573impl_heap_slice!(Box => AllocBox);
574impl_heap_slice!(Rc => AllocRc);
575impl_heap_slice!(Arc => AllocArc);
576
577#[cfg(feature = "alloc")]
578impl<T, Len> SchemaWrite for VecDeque<T, Len>
579where
580    Len: SeqLen,
581    T: SchemaWrite,
582    T::Src: Sized,
583{
584    type Src = collections::VecDeque<T::Src>;
585
586    #[inline(always)]
587    fn size_of(value: &Self::Src) -> WriteResult<usize> {
588        size_of_elem_iter::<T, Len>(value.iter())
589    }
590
591    #[inline(always)]
592    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
593        if let TypeMeta::Static {
594            size,
595            zero_copy: true,
596        } = T::TYPE_META
597        {
598            #[allow(clippy::arithmetic_side_effects)]
599            let needed = Len::write_bytes_needed(src.len())? + src.len() * size;
600            // SAFETY: `needed` is the size of the encoded length plus the size of the items.
601            // `Len::write` and `len` writes of `T::Src` will write `needed` bytes,
602            // fully initializing the trusted window.
603            let writer = &mut unsafe { writer.as_trusted_for(needed) }?;
604
605            Len::write(writer, src.len())?;
606            let (front, back) = src.as_slices();
607            // SAFETY:
608            // - `T` is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
609            // - `front` and `back` are valid non-overlapping slices.
610            unsafe {
611                writer.write_slice_t(front)?;
612                writer.write_slice_t(back)?;
613            }
614
615            writer.finish()?;
616
617            return Ok(());
618        }
619
620        write_elem_iter::<T, Len>(writer, src.iter())
621    }
622}
623
624#[cfg(feature = "alloc")]
625impl<'de, T, Len> SchemaRead<'de> for VecDeque<T, Len>
626where
627    Len: SeqLen,
628    T: SchemaRead<'de>,
629{
630    type Dst = collections::VecDeque<T::Dst>;
631
632    #[inline(always)]
633    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
634        // Leverage the contiguous read optimization of `Vec`.
635        // From<Vec<T>> for VecDeque<T> is basically free.
636        let vec = <Vec<T, Len>>::get(reader)?;
637        dst.write(vec.into());
638        Ok(())
639    }
640}
641
642#[cfg(feature = "alloc")]
643/// A [`BinaryHeap`](alloc::collections::BinaryHeap) with a customizable length encoding.
644pub struct BinaryHeap<T, Len = BincodeLen>(PhantomData<Len>, PhantomData<T>);
645
646#[cfg(feature = "alloc")]
647impl<T, Len> SchemaWrite for BinaryHeap<T, Len>
648where
649    Len: SeqLen,
650    T: SchemaWrite,
651    T::Src: Sized,
652{
653    type Src = collections::BinaryHeap<T::Src>;
654
655    #[inline(always)]
656    fn size_of(src: &Self::Src) -> WriteResult<usize> {
657        size_of_elem_slice::<T, Len>(src.as_slice())
658    }
659
660    #[inline(always)]
661    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
662        write_elem_slice::<T, Len>(writer, src.as_slice())
663    }
664}
665
666#[cfg(feature = "alloc")]
667impl<'de, T, Len> SchemaRead<'de> for BinaryHeap<T, Len>
668where
669    Len: SeqLen,
670    T: SchemaRead<'de>,
671    T::Dst: Ord,
672{
673    type Dst = collections::BinaryHeap<T::Dst>;
674
675    #[inline(always)]
676    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
677        let vec = <Vec<T, Len>>::get(reader)?;
678        // Leverage the vec impl.
679        dst.write(collections::BinaryHeap::from(vec));
680        Ok(())
681    }
682}