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_wrapper!`]).
4//!
5//! # Examples
6//! Raw byte vec with `UseIntLen<u16>` length encoding:
7//!
8//! ```
9//! # #[cfg(all(feature = "alloc", feature = "derive"))] {
10//! # use wincode::{containers, len::UseIntLen};
11//! # use wincode_derive::{SchemaWrite, SchemaRead};
12//! # use core::mem::size_of;
13//! #[derive(SchemaWrite, SchemaRead, PartialEq, Debug)]
14//! struct MyStruct {
15//! #[wincode(with = "containers::Vec<_, UseIntLen<u16>>")]
16//! vec: Vec<u8>,
17//! }
18//!
19//! let my_struct = MyStruct { vec: vec![1, 2, 3] };
20//! let bytes = wincode::serialize(&my_struct).unwrap();
21//! assert_eq!(bytes.len(), size_of::<u16>() + my_struct.vec.len() * size_of::<u8>());
22//! assert_eq!(my_struct, wincode::deserialize(&bytes).unwrap());
23//! # }
24//! ```
25//!
26//! Vector with struct elements and `UseIntLen<u16>` length encoding:
27//!
28//! ```
29//! # #[cfg(all(feature = "alloc", feature = "derive"))] {
30//! # use wincode::{containers, len::UseIntLen};
31//! # use wincode_derive::{SchemaWrite, SchemaRead};
32//! # use core::mem::size_of;
33//! #[derive(SchemaWrite, SchemaRead, PartialEq, Debug)]
34//! struct Point {
35//! x: u64,
36//! y: u64,
37//! }
38//!
39//! #[derive(SchemaWrite, SchemaRead, PartialEq, Debug)]
40//! struct MyStruct {
41//! #[wincode(with = "containers::Vec<Point, UseIntLen<u16>>")]
42//! vec: Vec<Point>,
43//! }
44//!
45//! let my_struct = MyStruct {
46//! vec: vec![Point { x: 1, y: 2 }, Point { x: 3, y: 4 }],
47//! };
48//! let bytes = wincode::serialize(&my_struct).unwrap();
49//! assert_eq!(bytes.len(), size_of::<u16>() + my_struct.vec.len() * size_of::<Point>());
50//! assert_eq!(my_struct, wincode::deserialize(&bytes).unwrap());
51//! # }
52//! ```
53#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
54use alloc::sync::Arc as AllocArc;
55use {
56 crate::{
57 TypeMeta,
58 config::ConfigCore,
59 error::{ReadResult, WriteResult},
60 io::{Reader, Writer},
61 len::SeqLen,
62 schema::{SchemaRead, SchemaWrite, size_of_elem_iter, write_elem_iter},
63 },
64 core::{
65 borrow::Borrow,
66 marker::PhantomData,
67 mem::{self, MaybeUninit},
68 ptr,
69 },
70};
71#[cfg(feature = "alloc")]
72use {
73 crate::{
74 context,
75 schema::{
76 SchemaReadContext, size_of_elem_slice, write_elem_iter_prealloc_check,
77 write_elem_slice_prealloc_check,
78 },
79 },
80 alloc::{boxed::Box as AllocBox, collections, rc::Rc as AllocRc, vec},
81};
82
83/// A [`Vec`](std::vec::Vec) with a customizable length encoding.
84#[cfg(feature = "alloc")]
85pub struct Vec<T, Len>(PhantomData<Len>, PhantomData<T>);
86
87/// A [`VecDeque`](std::collections::VecDeque) with a customizable length encoding.
88#[cfg(feature = "alloc")]
89pub struct VecDeque<T, Len>(PhantomData<Len>, PhantomData<T>);
90
91/// A [`Box<[T]>`](std::boxed::Box) with a customizable length encoding.
92///
93/// # Examples
94///
95/// ```
96/// # #[cfg(all(feature = "alloc", feature = "derive"))] {
97/// # use wincode::{containers, len::UseIntLen};
98/// # use wincode_derive::{SchemaWrite, SchemaRead};
99/// # use core::{array, mem::size_of};
100/// #[derive(SchemaWrite, SchemaRead, Clone, Copy, PartialEq, Debug)]
101/// #[repr(transparent)]
102/// struct Address([u8; 32]);
103///
104/// #[derive(SchemaWrite, SchemaRead, PartialEq, Debug)]
105/// struct MyStruct {
106/// #[wincode(with = "containers::Box<[Address], UseIntLen<u16>>")]
107/// address: Box<[Address]>,
108/// }
109///
110/// let my_struct = MyStruct {
111/// address: vec![Address(array::from_fn(|i| i as u8)); 10].into_boxed_slice(),
112/// };
113/// let bytes = wincode::serialize(&my_struct).unwrap();
114/// assert_eq!(bytes.len(), size_of::<u16>() + my_struct.address.len() * size_of::<Address>());
115/// assert_eq!(my_struct, wincode::deserialize(&bytes).unwrap());
116/// # }
117/// ```
118#[cfg(feature = "alloc")]
119pub struct Box<T: ?Sized, Len>(PhantomData<T>, PhantomData<Len>);
120
121#[cfg(feature = "alloc")]
122/// Like [`Box`], for [`Rc`].
123pub struct Rc<T: ?Sized, Len>(PhantomData<T>, PhantomData<Len>);
124
125#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
126/// Like [`Box`], for [`Arc`].
127pub struct Arc<T: ?Sized, Len>(PhantomData<T>, PhantomData<Len>);
128
129/// Creates a wrapper type for a type that is represented by raw bytes and does not have any invalid
130/// bit patterns.
131///
132/// By using `pod_wrapper!`, you are telling wincode that it can serialize and deserialize a type
133/// with a single memcpy -- it wont pay attention to things like struct layout, endianness, or
134/// anything else that would require validity or bit pattern checks. This is a very strong claim to
135/// make, so be sure that your type adheres to those requirements.
136///
137/// Composable with sequence [`containers`](self) or compound types (structs, tuples) for
138/// an optimized read/write implementation.
139///
140/// This can be useful outside of sequences as well, for example on newtype structs
141/// containing byte arrays with `#[repr(transparent)]`.
142///
143/// ---
144/// 💡 **Note:** as of `wincode` `0.2.0`, `pod_wrapper!` is no longer needed for types that wincode
145/// can determine are "memcpy-safe".
146///
147/// This includes:
148/// - [`u8`]
149/// - [`[u8; N]`](prim@array)
150/// - structs comprised of the above, and;
151/// - annotated with `#[derive(SchemaWrite)]` or `#[derive(SchemaRead)]`, and;
152/// - annotated with `#[repr(transparent)]` or `#[repr(C)]`.
153///
154/// Similarly, using built-in std collections like `Vec<T>` or `Box<[T]>` where `T` is one of the
155/// above will also be automatically optimized.
156///
157/// You'll really only need to reach for [`pod_wrapper!`] when dealing with foreign types for which
158/// you cannot derive `SchemaWrite` or `SchemaRead`. Or you're in a controlled scenario where you
159/// explicitly want to avoid endianness or layout checks.
160///
161/// # Safety
162///
163/// - The type must allow any bit pattern (e.g., no `bool`s, no `char`s, etc.)
164/// - If used on a compound type like a struct, all fields must be also be memcpy-able, its layout
165/// must be guaranteed (via `#[repr(transparent)]` or `#[repr(C)]`), and the struct must not have
166/// any padding.
167/// - Must not contain references or pointers (includes types like `Vec` or `Box`).
168/// - Note, you may use `pod_wrapper!` created types *inside* types like `Vec` or `Box`, e.g.,
169/// `Vec<PodT>` or `Box<[PodT]>`, but using `pod_wrapper!` on the outer type is invalid.
170///
171/// # Examples
172///
173/// A repr-transparent newtype struct containing a byte array where you cannot derive `SchemaWrite`
174/// or `SchemaRead`:
175/// ```
176/// # #[cfg(all(feature = "alloc", feature = "derive"))] {
177/// # use wincode::containers;
178/// # use wincode_derive::{SchemaWrite, SchemaRead};
179/// # use serde::{Serialize, Deserialize};
180/// # use std::array;
181/// #[derive(Serialize, Deserialize, Clone, Copy)]
182/// #[repr(transparent)]
183/// struct Address([u8; 32]);
184///
185/// wincode::pod_wrapper! {
186/// unsafe struct PodAddress(Address);
187/// }
188///
189/// #[derive(Serialize, Deserialize, SchemaWrite, SchemaRead)]
190/// struct MyStruct {
191/// #[wincode(with = "PodAddress")]
192/// address: Address
193/// }
194///
195/// let my_struct = MyStruct {
196/// address: Address(array::from_fn(|i| i as u8)),
197/// };
198/// let wincode_bytes = wincode::serialize(&my_struct).unwrap();
199/// let bincode_bytes = bincode::serialize(&my_struct).unwrap();
200/// assert_eq!(wincode_bytes, bincode_bytes);
201/// # }
202/// ```
203#[macro_export]
204macro_rules! pod_wrapper {
205 ($(unsafe struct $name:ident($type:ty);)*) => {$(
206 struct $name where $type: Copy + 'static;
207
208 // SAFETY:
209 // - By using `pod_wrapper`, user asserts that the type is zero-copy, given the contract of
210 // pod_wrapper:
211 // - The type's in‑memory representation is exactly its serialized bytes.
212 // - It can be safely initialized by memcpy (no validation, no endianness/layout work).
213 // - Does not contain references or pointers.
214 unsafe impl<C: $crate::config::ConfigCore> $crate::config::ZeroCopy<C> for $name {}
215
216 unsafe impl<C: $crate::config::ConfigCore> $crate::SchemaWrite<C> for $name {
217 type Src = $type;
218
219 const TYPE_META: $crate::TypeMeta = $crate::TypeMeta::Static {
220 size: size_of::<$type>(),
221 zero_copy: true,
222 };
223
224 #[inline]
225 fn size_of(_: &$type) -> $crate::WriteResult<usize> {
226 Ok(size_of::<$type>())
227 }
228
229 #[inline]
230 fn write(mut writer: impl $crate::io::Writer, src: &$type) -> $crate::WriteResult<()> {
231 unsafe {
232 Ok(writer.write_t(src)?)
233 }
234 }
235 }
236
237 unsafe impl<'de, C: $crate::config::ConfigCore> $crate::SchemaRead<'de, C> for $name {
238 type Dst = $type;
239
240 const TYPE_META: $crate::TypeMeta = $crate::TypeMeta::Static {
241 size: size_of::<$type>(),
242 zero_copy: true,
243 };
244
245 fn read(mut reader: impl $crate::io::Reader<'de>, dst: &mut core::mem::MaybeUninit<$type>) -> $crate::ReadResult<()> {
246 unsafe {
247 Ok(reader.copy_into_t(dst)?)
248 }
249 }
250 }
251 )*}
252}
253pub use pod_wrapper;
254
255#[cfg(feature = "alloc")]
256unsafe impl<T, Len, C: ConfigCore> SchemaWrite<C> for Vec<T, Len>
257where
258 Len: SeqLen<C>,
259 T: SchemaWrite<C>,
260 T::Src: Sized,
261{
262 type Src = vec::Vec<T::Src>;
263
264 #[inline(always)]
265 fn size_of(src: &Self::Src) -> WriteResult<usize> {
266 size_of_elem_slice::<T, Len, C>(src)
267 }
268
269 #[inline(always)]
270 fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
271 write_elem_slice_prealloc_check::<T, Len, C>(writer, src)
272 }
273}
274
275#[cfg(feature = "alloc")]
276unsafe impl<'de, T, Len, C: ConfigCore> SchemaRead<'de, C> for Vec<T, Len>
277where
278 Len: SeqLen<C>,
279 T: SchemaRead<'de, C>,
280{
281 type Dst = vec::Vec<T::Dst>;
282
283 #[inline]
284 fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
285 let len = Len::read_prealloc_check::<T::Dst>(reader.by_ref())?;
286 <vec::Vec<T>>::read_with_context(context::Len(len), reader, dst)?;
287 Ok(())
288 }
289}
290
291pub(crate) struct SliceDropGuard<T> {
292 ptr: *mut MaybeUninit<T>,
293 initialized_len: usize,
294}
295
296impl<T> SliceDropGuard<T> {
297 pub(crate) fn new(ptr: *mut MaybeUninit<T>) -> Self {
298 Self {
299 ptr,
300 initialized_len: 0,
301 }
302 }
303
304 #[inline(always)]
305 #[allow(clippy::arithmetic_side_effects)]
306 pub(crate) fn inc_len(&mut self) {
307 if mem::needs_drop::<T>() {
308 self.initialized_len += 1;
309 }
310 }
311}
312
313impl<T> Drop for SliceDropGuard<T> {
314 #[cold]
315 fn drop(&mut self) {
316 if mem::needs_drop::<T>() {
317 unsafe {
318 ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
319 self.ptr.cast::<T>(),
320 self.initialized_len,
321 ));
322 }
323 }
324 }
325}
326
327/// Returns a mutable reference into the given Arc, without any check.
328///
329/// # Safety
330///
331/// If any other `Arc` or `Weak` pointers to the same allocation exist, then
332/// they must not be dereferenced or have active borrows for the duration
333/// of the returned borrow, and their inner type must be exactly the same as the
334/// inner type of this Arc (including lifetimes). This is trivially the case if no
335/// such pointers exist, for example immediately after `Arc::new`.
336#[inline]
337#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
338unsafe fn arc_get_mut_unchecked<T: ?Sized>(arc: &mut AllocArc<T>) -> &mut T {
339 unsafe { &mut *AllocArc::as_ptr(arc).cast_mut() }
340}
341
342/// Returns a mutable reference into the given `Rc`,
343/// without any check.
344///
345/// # Safety
346///
347/// If any other `Rc` or `Weak` pointers to the same allocation exist, then
348/// they must not be dereferenced or have active borrows for the duration
349/// of the returned borrow, and their inner type must be exactly the same as the
350/// inner type of this Rc (including lifetimes). This is trivially the case if no
351/// such pointers exist, for example immediately after `Rc::new`.
352#[inline]
353#[cfg(feature = "alloc")]
354unsafe fn rc_get_mut_unchecked<T: ?Sized>(rc: &mut AllocRc<T>) -> &mut T {
355 unsafe { &mut *AllocRc::as_ptr(rc).cast_mut() }
356}
357
358macro_rules! impl_heap_slice {
359 ($container:ident => $target:ident, |$uninit:ident| $get_slice:expr) => {
360 #[cfg(feature = "alloc")]
361 unsafe impl<T, Len, C: ConfigCore> SchemaWrite<C> for $container<[T], Len>
362 where
363 Len: SeqLen<C>,
364 T: SchemaWrite<C>,
365 T::Src: Sized,
366 {
367 type Src = $target<[T::Src]>;
368
369 #[inline(always)]
370 fn size_of(src: &Self::Src) -> WriteResult<usize> {
371 size_of_elem_slice::<T, Len, C>(src)
372 }
373
374 #[inline(always)]
375 fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
376 write_elem_slice_prealloc_check::<T, Len, C>(writer, src)
377 }
378 }
379
380 #[cfg(feature = "alloc")]
381 unsafe impl<'de, T, Len, C: ConfigCore> SchemaRead<'de, C> for $container<[T], Len>
382 where
383 Len: SeqLen<C>,
384 T: SchemaRead<'de, C>,
385 {
386 type Dst = $target<[T::Dst]>;
387
388 #[inline(always)]
389 fn read(
390 mut reader: impl Reader<'de>,
391 dst: &mut MaybeUninit<Self::Dst>,
392 ) -> ReadResult<()> {
393 let len = Len::read_prealloc_check::<T::Dst>(reader.by_ref())?;
394 let mut $uninit = $target::<[T::Dst]>::new_uninit_slice(len);
395 decode_into_slice_t::<T, C>(reader, $get_slice)?;
396 // SAFETY: `decode_into_slice_t` initialized all elements on success.
397 let container = unsafe { $uninit.assume_init() };
398 dst.write(container);
399 Ok(())
400 }
401 }
402 };
403}
404
405impl_heap_slice!(Box => AllocBox, |uninit| &mut *uninit);
406impl_heap_slice!(Rc => AllocRc, |uninit| unsafe { rc_get_mut_unchecked(&mut uninit) });
407#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
408impl_heap_slice!(Arc => AllocArc, |uninit| unsafe { arc_get_mut_unchecked(&mut uninit) });
409
410#[cfg(feature = "alloc")]
411unsafe impl<T, Len, C: ConfigCore> SchemaWrite<C> for VecDeque<T, Len>
412where
413 Len: SeqLen<C>,
414 T: SchemaWrite<C>,
415 T::Src: Sized,
416{
417 type Src = collections::VecDeque<T::Src>;
418
419 #[inline(always)]
420 fn size_of(value: &Self::Src) -> WriteResult<usize> {
421 size_of_elem_iter::<T, Len, C>(value.iter())
422 }
423
424 #[inline(always)]
425 fn write(mut writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
426 if let TypeMeta::Static {
427 size,
428 zero_copy: true,
429 } = T::TYPE_META
430 {
431 #[allow(clippy::arithmetic_side_effects)]
432 let needed =
433 Len::write_bytes_needed_prealloc_check::<T::Src>(src.len())? + src.len() * size;
434 // SAFETY: `needed` is the size of the encoded length plus the size of the items.
435 // `Len::write` and `len` writes of `T::Src` will write `needed` bytes,
436 // fully initializing the trusted window.
437 let mut writer = unsafe { writer.as_trusted_for(needed) }?;
438
439 Len::write(writer.by_ref(), src.len())?;
440 let (front, back) = src.as_slices();
441 // SAFETY:
442 // - `T` is zero-copy eligible (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
443 // - `front` and `back` are valid non-overlapping slices.
444 unsafe {
445 writer.write_slice_t(front)?;
446 writer.write_slice_t(back)?;
447 }
448
449 writer.finish()?;
450
451 return Ok(());
452 }
453
454 write_elem_iter_prealloc_check::<T, Len, C>(writer, src.iter())
455 }
456}
457
458#[cfg(feature = "alloc")]
459unsafe impl<'de, T, Len, C: ConfigCore> SchemaRead<'de, C> for VecDeque<T, Len>
460where
461 Len: SeqLen<C>,
462 T: SchemaRead<'de, C>,
463{
464 type Dst = collections::VecDeque<T::Dst>;
465
466 #[inline(always)]
467 fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
468 // Leverage the contiguous read optimization of `Vec`.
469 // From<Vec<T>> for VecDeque<T> is basically free.
470 let vec = <Vec<T, Len>>::get(reader)?;
471 dst.write(vec.into());
472 Ok(())
473 }
474}
475
476#[cfg(feature = "alloc")]
477/// A [`BinaryHeap`](alloc::collections::BinaryHeap) with a customizable length encoding.
478pub struct BinaryHeap<T, Len>(PhantomData<Len>, PhantomData<T>);
479
480#[cfg(feature = "alloc")]
481unsafe impl<T, Len, C: ConfigCore> SchemaWrite<C> for BinaryHeap<T, Len>
482where
483 Len: SeqLen<C>,
484 T: SchemaWrite<C>,
485 T::Src: Sized,
486{
487 type Src = collections::BinaryHeap<T::Src>;
488
489 #[inline(always)]
490 fn size_of(src: &Self::Src) -> WriteResult<usize> {
491 size_of_elem_slice::<T, Len, C>(src.as_slice())
492 }
493
494 #[inline(always)]
495 fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
496 write_elem_slice_prealloc_check::<T, Len, C>(writer, src.as_slice())
497 }
498}
499
500#[cfg(feature = "alloc")]
501unsafe impl<'de, T, Len, C: ConfigCore> SchemaRead<'de, C> for BinaryHeap<T, Len>
502where
503 Len: SeqLen<C>,
504 T: SchemaRead<'de, C>,
505 T::Dst: Ord,
506{
507 type Dst = collections::BinaryHeap<T::Dst>;
508
509 #[inline(always)]
510 fn read(reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
511 let vec = <Vec<T, Len>>::get(reader)?;
512 // Leverage the vec impl.
513 dst.write(collections::BinaryHeap::from(vec));
514 Ok(())
515 }
516}
517
518/// Newtype that collects a fallible iterator into `Result<C, E>` while preserving `size_hint`.
519///
520/// Unlike `collect::<Result<V, E>>()`, which loses the size hint on error, this type
521/// drives `V::from_iter` through an adaptor that stops on the first error but keeps
522/// `size_hint` accurate so that `V` can preallocate its full expected capacity.
523struct ResultPrealloc<T, E>(Result<T, E>);
524
525impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for ResultPrealloc<V, E> {
526 fn from_iter<I: IntoIterator<Item = Result<A, E>>>(iter: I) -> ResultPrealloc<V, E> {
527 struct Iter<I, E> {
528 inner: I,
529 error: Option<E>,
530 }
531
532 impl<I: Iterator<Item = Result<T, E>>, T, E> Iterator for Iter<I, E> {
533 type Item = T;
534
535 #[inline]
536 fn next(&mut self) -> Option<Self::Item> {
537 self.inner.next()?.map_err(|e| self.error = Some(e)).ok()
538 }
539
540 #[inline]
541 fn size_hint(&self) -> (usize, Option<usize>) {
542 self.inner.size_hint()
543 }
544 }
545
546 let mut iter = Iter {
547 inner: iter.into_iter(),
548 error: None,
549 };
550 let result = V::from_iter(&mut iter);
551 ResultPrealloc(iter.error.map_or(Ok(result), Err))
552 }
553}
554
555/// Extension trait that adds [`collect_result_prealloc`](CollectResultExt::collect_result_prealloc)
556/// to any fallible iterator, collecting into `Result<B, E>` with preallocation-friendly size hints.
557trait CollectResultExt<T, E>: Iterator<Item = Result<T, E>> {
558 #[inline]
559 fn collect_result_prealloc<B: FromIterator<T>>(self) -> Result<B, E>
560 where
561 Self: Sized,
562 {
563 self.collect::<ResultPrealloc<B, E>>().0
564 }
565}
566impl<T, E, I> CollectResultExt<T, E> for I where I: Iterator<Item = Result<T, E>> {}
567
568/// A generic sequence schema for custom collections that implement
569/// [`FromIterator`] (for reading) and whose references implement
570/// [`IntoIterator`] with an [`ExactSizeIterator`] (for writing).
571///
572/// Works for both element sequences and key-value maps:
573/// - For element collections (sets, ordered sets, etc.) whose reference
574/// iterators yield `&T`, the schema for `T` is used directly.
575/// - For map-like collections whose reference iterators yield `(&K, &V)` pairs,
576/// the pair itself acts as the schema (automatically satisfied when `K` and
577/// `V` implement `SchemaWrite<C>`).
578///
579/// Intended for external collection types that cannot have a dedicated
580/// schema impl added directly. Unlike [`Vec`], [`VecDeque`], and [`BinaryHeap`], this
581/// container relies on the collection's [`FromIterator`] impl rather than
582/// writing directly into preallocated memory.
583///
584/// For manual [`SchemaWrite`] implementations that emit a sequence from an
585/// ad-hoc iterator rather than a concrete collection, see
586/// [`encode_from_iter_prealloc_check`] (and its check-skipping counterpart
587/// [`encode_from_iter`]).
588///
589/// # Allocation efficiency
590///
591/// During deserialization, the iterator passed to [`FromIterator`] has a
592/// precise [`size_hint`](Iterator::size_hint) matching the number of elements
593/// produced, unless a read error is encountered. Collections whose
594/// [`FromIterator`] implementation uses the size hint to preallocate capacity
595/// will allocate optimally. Collections that do not use it will not benefit.
596///
597/// # Examples
598///
599/// ```ignore
600/// use some_crate::{IndexSet, MyMap};
601/// use wincode::{SchemaRead, SchemaWrite, containers::FromIntoIterator, len::BincodeLen};
602///
603/// #[derive(SchemaRead, SchemaWrite)]
604/// struct MyData {
605/// #[wincode(with = "FromIntoIterator<IndexSet<u32>, BincodeLen>")]
606/// items: IndexSet<u32>,
607/// #[wincode(with = "FromIntoIterator<MyMap<u32, u64>, BincodeLen>")]
608/// map: MyMap<u32, u64>,
609/// }
610/// ```
611pub struct FromIntoIterator<Coll, Len>(PhantomData<(Coll, Len)>);
612
613unsafe impl<Coll, Len, C: ConfigCore> SchemaWrite<C> for FromIntoIterator<Coll, Len>
614where
615 Len: SeqLen<C>,
616 Coll: IntoIterator,
617 for<'a> &'a Coll: IntoIterator<Item: SchemaWrite<C>, IntoIter: ExactSizeIterator>,
618 for<'a> <&'a Coll as IntoIterator>::Item:
619 Borrow<<<&'a Coll as IntoIterator>::Item as SchemaWrite<C>>::Src>,
620{
621 type Src = Coll;
622
623 #[inline]
624 fn size_of(src: &Coll) -> WriteResult<usize> {
625 size_of_elem_iter::<<&Coll as IntoIterator>::Item, Len, C>(src.into_iter())
626 }
627
628 #[inline]
629 fn write(writer: impl Writer, src: &Coll) -> WriteResult<()> {
630 let iter = src.into_iter();
631 Len::prealloc_check::<Coll::Item>(iter.len())?;
632 write_elem_iter::<<&Coll as IntoIterator>::Item, Len, C>(writer, iter)
633 }
634}
635
636unsafe impl<'de, Coll, Len, C: ConfigCore> SchemaRead<'de, C> for FromIntoIterator<Coll, Len>
637where
638 Len: SeqLen<C>,
639 Coll: IntoIterator<Item: SchemaRead<'de, C>>,
640 Coll: FromIterator<<Coll::Item as SchemaRead<'de, C>>::Dst>,
641{
642 type Dst = Coll;
643
644 #[inline]
645 fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Coll>) -> ReadResult<()> {
646 let len =
647 Len::read_prealloc_check::<<Coll::Item as SchemaRead<'de, C>>::Dst>(reader.by_ref())?;
648
649 let coll = if let TypeMeta::Static { size, .. } = Coll::Item::TYPE_META {
650 // SAFETY: `Item::TYPE_META` specifies a static size, so `len` reads of `Item::Dst`
651 // will consume `size * len` bytes, fully consuming the trusted window.
652 let mut reader = unsafe { reader.as_trusted_for_seq(len, size) }?;
653 (0..len)
654 .map(|_| Coll::Item::get(reader.by_ref()))
655 .collect_result_prealloc()?
656 } else {
657 (0..len)
658 .map(|_| Coll::Item::get(reader.by_ref()))
659 .collect_result_prealloc()?
660 };
661 dst.write(coll);
662 Ok(())
663 }
664}
665
666/// Decode `slice.len()` items of `T` into contiguous, uninitialized memory.
667///
668/// Errors if fewer than `slice.len()` items are available in the [`Reader`]
669/// or any item fails to decode.
670///
671/// On success, every slot in `slice` is initialized.
672/// On error or panic, any elements that were initialized before failure are
673/// dropped, and the remaining slots stay uninitialized.
674///
675/// # Examples
676///
677/// ```
678/// # #[cfg(feature = "alloc")] {
679/// # use wincode::containers::decode_into_slice_t;
680/// # use wincode::config::DefaultConfig;
681/// # type C = DefaultConfig;
682/// let data = [1u64, 2, 3, 4, 5, 6];
683/// let serialized = wincode::serialize(&data).unwrap();
684///
685/// let mut dst: Vec<u64> = Vec::with_capacity(6);
686///
687/// decode_into_slice_t::<u64, C>(
688/// &serialized[..],
689/// &mut dst.spare_capacity_mut()[..6],
690/// )
691/// .unwrap();
692///
693/// unsafe { dst.set_len(6) }
694///
695/// assert_eq!(dst, data);
696/// # }
697/// ```
698///
699/// ```
700/// # #[cfg(feature = "alloc")] {
701/// # use wincode::containers::decode_into_slice_t;
702/// # use wincode::config::DefaultConfig;
703/// # type C = DefaultConfig;
704/// let data = [1u64, 2, 3, 4, 5, 6];
705/// let serialized = wincode::serialize(&data).unwrap();
706///
707/// let mut dst: Vec<u64> = Vec::with_capacity(7);
708///
709/// let result = decode_into_slice_t::<u64, C>(
710/// &serialized[..],
711/// &mut dst.spare_capacity_mut()[..7],
712/// );
713///
714/// // Only 6 elements were serialized.
715/// assert!(result.is_err());
716/// # }
717/// ```
718#[inline]
719pub fn decode_into_slice_t<'de, T, C>(
720 mut reader: impl Reader<'de>,
721 slice: &mut [MaybeUninit<T::Dst>],
722) -> ReadResult<()>
723where
724 T: SchemaRead<'de, C>,
725 C: ConfigCore,
726{
727 let base = slice.as_mut_ptr();
728 let len = slice.len();
729 let mut guard = SliceDropGuard::<T::Dst>::new(base);
730
731 match T::TYPE_META {
732 TypeMeta::Static {
733 zero_copy: true, ..
734 } => {
735 // SAFETY: `zero_copy: true` guarantees `T::Dst` is zero-copy eligible
736 // (no invalid bit patterns, no layout requirements, no endianness checks, etc.).
737 unsafe { reader.copy_into_slice_t(slice) }?
738 }
739 TypeMeta::Static {
740 size,
741 zero_copy: false,
742 } => {
743 // SAFETY: `T::TYPE_META` specifies a static size, so `len` reads of `T::Dst`
744 // will consume `size * len` bytes, fully consuming the trusted window.
745 let mut reader = unsafe { reader.as_trusted_for_seq(len, size) }?;
746 for i in 0..len {
747 // SAFETY: `i < len` and `base` is valid for `len` elements.
748 let slot = unsafe { &mut *base.add(i) };
749 T::read(reader.by_ref(), slot)?;
750 guard.inc_len();
751 }
752 }
753 TypeMeta::Dynamic => {
754 for i in 0..len {
755 // SAFETY: `i < len` and `base` is valid for `len` elements.
756 let slot = unsafe { &mut *base.add(i) };
757 T::read(reader.by_ref(), slot)?;
758 guard.inc_len();
759 }
760 }
761 }
762
763 mem::forget(guard);
764 Ok(())
765}
766
767/// Encode a sequence of `T` from an iterator into the [`Writer`].
768///
769/// Writes the sequence length (encoded per `Len`) followed by each item
770/// yielded by `src`. This is the encoding counterpart of the full sequence
771/// read performed by container types such as [`Vec`]: the produced wire format
772/// is identical to serializing a `Vec<T::Src>` (or any other sequence) with the
773/// same element type `T`, length encoding `Len`, and configuration `C`.
774///
775/// `src` is any [`IntoIterator`] whose iterator is an [`ExactSizeIterator`], so
776/// a sequence can be encoded directly from a lazily-produced iterator (a range,
777/// a `map`/`filter` chain, borrowed views into several sources, …) without
778/// first materializing it into a collection.
779///
780/// # Comparison with [`FromIntoIterator`]
781///
782/// [`FromIntoIterator`] is a [`with`](crate)-adapter: it plugs an existing
783/// collection type that exposes the standard [`IntoIterator`]/[`FromIterator`]
784/// trait shape into a derived [`SchemaWrite`]/[`SchemaRead`] impl. Reach for it
785/// when you have a concrete container to (de)serialize through a field
786/// attribute.
787///
788/// `encode_from_iter_prealloc_check` is the lower-level building block for
789/// *manual* [`SchemaWrite`] implementations: it lets you emit a sequence from an
790/// ad-hoc iterator without needing a collection that implements those traits.
791///
792/// # Preallocation check
793///
794/// Before encoding, this validates the length against the configured
795/// preallocation limit (see [`SeqLen::prealloc_check`]) and returns an error if
796/// it would be exceeded. This mirrors [`SeqLen::read_prealloc_check`], which is
797/// applied on deserialization, so a wire format produced here is guaranteed to
798/// be accepted on read-back under the *same* configuration `C` and length
799/// encoding `Len`. This is the recommended entry point; use
800/// [`encode_from_iter`] only when the check is undesirable or has already been
801/// performed.
802///
803/// # Examples
804///
805/// ```
806/// # #[cfg(feature = "alloc")] {
807/// use wincode::config::{Config, DefaultConfig};
808/// use wincode::containers::encode_from_iter_prealloc_check;
809/// use wincode::io::Writer;
810///
811/// type C = DefaultConfig;
812/// type Len = <C as Config>::LengthEncoding;
813///
814/// // Encode 0², 1², … 5² straight from a lazy iterator — the sequence is
815/// // never materialized into an intermediate `Vec`.
816/// let mut buf = Vec::new();
817/// encode_from_iter_prealloc_check::<u32, Len, C>(buf.by_ref(), (0u32..6).map(|i| i * i))
818/// .unwrap();
819///
820/// assert_eq!(wincode::deserialize::<Vec<u32>>(&buf).unwrap(), [0, 1, 4, 9, 16, 25]);
821/// # }
822/// ```
823#[cfg(feature = "alloc")]
824#[inline]
825pub fn encode_from_iter_prealloc_check<T, Len, C>(
826 writer: impl Writer,
827 src: impl IntoIterator<IntoIter: ExactSizeIterator, Item: Borrow<T::Src>>,
828) -> WriteResult<()>
829where
830 C: ConfigCore,
831 Len: SeqLen<C>,
832 T: SchemaWrite<C>,
833 T::Src: Sized,
834{
835 write_elem_iter_prealloc_check::<T, Len, C>(writer, src.into_iter())
836}
837
838/// Like [`encode_from_iter_prealloc_check`], but **skips** the preallocation
839/// size check.
840///
841/// Use this only when the check is undesirable, or when you have already
842/// validated the length yourself via [`SeqLen::prealloc_check`]. Because no
843/// check is performed here, the produced length may exceed the configured
844/// preallocation limit and be rejected on deserialization by
845/// [`SeqLen::read_prealloc_check`]; prefer [`encode_from_iter_prealloc_check`]
846/// unless you specifically need to bypass the check.
847///
848/// See [`encode_from_iter_prealloc_check`] for details on the wire format and
849/// how this relates to [`FromIntoIterator`].
850///
851/// # Examples
852///
853/// ```
854/// # #[cfg(feature = "alloc")] {
855/// use wincode::config::{Config, DefaultConfig};
856/// use wincode::containers::encode_from_iter;
857/// use wincode::io::Writer;
858/// use wincode::len::SeqLen;
859///
860/// type C = DefaultConfig;
861/// type Len = <C as Config>::LengthEncoding;
862///
863/// let squares = (0u32..6).map(|i| i * i);
864///
865/// // The caller is responsible for the preallocation check when using this
866/// // variant, so the same configuration accepts the result on deserialization.
867/// assert!(<Len as SeqLen<C>>::prealloc_check::<u32>(squares.len()).is_ok());
868///
869/// let mut buf = Vec::new();
870/// encode_from_iter::<u32, Len, C>(buf.by_ref(), squares).unwrap();
871///
872/// assert_eq!(wincode::deserialize::<Vec<u32>>(&buf).unwrap(), [0, 1, 4, 9, 16, 25]);
873/// # }
874/// ```
875#[inline]
876pub fn encode_from_iter<T, Len, C>(
877 writer: impl Writer,
878 src: impl IntoIterator<IntoIter: ExactSizeIterator, Item: Borrow<T::Src>>,
879) -> WriteResult<()>
880where
881 C: ConfigCore,
882 Len: SeqLen<C>,
883 T: SchemaWrite<C>,
884{
885 write_elem_iter::<T, Len, C>(writer, src.into_iter())
886}