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}