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}