Skip to main content

wincode/config/
serde.rs

1//! Configuration-aware serialize / deserialize traits and functions.
2#[cfg(feature = "alloc")]
3use alloc::vec::Vec;
4use {
5    crate::{
6        ReadResult, SchemaRead, SchemaReadContext, SchemaReadOwned, SchemaWrite, WriteResult,
7        config::{Config, ConfigCore},
8        error,
9        io::{Reader, Writer},
10    },
11    core::mem::MaybeUninit,
12};
13
14/// Like [`crate::Serialize`], but allows the caller to provide a custom configuration.
15pub trait Serialize<C: Config>: SchemaWrite<C> {
16    /// Serialize a serializable type into a `Vec` of bytes.
17    #[cfg(feature = "alloc")]
18    fn serialize(src: &Self::Src, config: C) -> WriteResult<Vec<u8>> {
19        let capacity = Self::size_of(src)?;
20        let mut buffer = Vec::with_capacity(capacity);
21        let mut writer = buffer.spare_capacity_mut();
22        Self::serialize_into(writer.by_ref(), src, config)?;
23        let len = writer.len();
24        unsafe {
25            #[allow(clippy::arithmetic_side_effects)]
26            buffer.set_len(capacity - len);
27        }
28        Ok(buffer)
29    }
30
31    /// Serialize a serializable type into the given [`Writer`].
32    ///
33    /// # Partial writes
34    ///
35    /// This operation is not transactional. If it returns an error, the writer
36    /// may already contain a prefix of the serialized value. Dynamically sized
37    /// values in particular may discover insufficient capacity only after
38    /// preceding fields have been written.
39    ///
40    /// If the destination must remain unchanged on failure, serialize into a
41    /// temporary buffer and copy the result only after serialization succeeds.
42    /// For a fixed-size destination, callers can instead use
43    /// [`Self::serialized_size`] with the same configuration to check that
44    /// enough space is available first.
45    #[inline]
46    #[expect(unused_variables)]
47    fn serialize_into(mut dst: impl Writer, src: &Self::Src, config: C) -> WriteResult<()> {
48        Self::write(dst.by_ref(), src)?;
49        dst.finish()?;
50        Ok(())
51    }
52
53    /// Get the size in bytes of the type when serialized.
54    #[inline]
55    #[expect(unused_variables)]
56    fn serialized_size(src: &Self::Src, config: C) -> WriteResult<u64> {
57        Self::size_of(src).map(|size| size as u64)
58    }
59}
60
61impl<T, C: Config> Serialize<C> for T where T: SchemaWrite<C> + ?Sized {}
62
63/// Like [`crate::Deserialize`], but allows the caller to provide a custom configuration.
64pub trait Deserialize<'de, C: Config>: SchemaRead<'de, C> {
65    /// Deserialize the input bytes into a new `Self::Dst`.
66    #[inline(always)]
67    #[expect(unused_variables)]
68    fn deserialize(src: &'de [u8], config: C) -> ReadResult<Self::Dst> {
69        Self::get(src)
70    }
71
72    /// Deserialize the input bytes into `dst`.
73    #[inline]
74    #[expect(unused_variables)]
75    fn deserialize_into(
76        src: &'de [u8],
77        dst: &mut MaybeUninit<Self::Dst>,
78        config: C,
79    ) -> ReadResult<()> {
80        Self::read(src, dst)
81    }
82}
83
84impl<'de, T, C: Config> Deserialize<'de, C> for T where T: SchemaRead<'de, C> {}
85
86/// Like [`crate::DeserializeOwned`], but allows the caller to provide a custom configuration.
87pub trait DeserializeOwned<C: Config>: SchemaReadOwned<C> {
88    /// Deserialize from the given [`Reader`] into a new `Self::Dst`.
89    #[inline(always)]
90    fn deserialize_from<'de>(
91        src: impl Reader<'de>,
92    ) -> ReadResult<<Self as SchemaRead<'de, C>>::Dst> {
93        Self::get(src)
94    }
95
96    /// Deserialize from the given [`Reader`] into `dst`.
97    #[inline]
98    fn deserialize_from_into<'de>(
99        src: impl Reader<'de>,
100        dst: &mut MaybeUninit<<Self as SchemaRead<'de, C>>::Dst>,
101    ) -> ReadResult<()> {
102        Self::read(src, dst)
103    }
104}
105
106impl<T, C: Config> DeserializeOwned<C> for T where T: SchemaReadOwned<C> {}
107
108/// Like [`crate::serialize`], but allows the caller to provide a custom configuration.
109///
110/// # Examples
111///
112/// ```
113/// # #[cfg(feature = "alloc")] {
114/// # use wincode::{config::Configuration, len::FixIntLen};
115/// let config = Configuration::default().with_length_encoding::<FixIntLen<u32>>();
116/// let vec: Vec<u8> = vec![1, 2, 3];
117/// let bytes = wincode::config::serialize(&vec, config).unwrap();
118/// assert_eq!(vec.len(), u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as usize);
119/// # }
120/// ```
121#[cfg(feature = "alloc")]
122pub fn serialize<T, C: Config>(src: &T, config: C) -> WriteResult<Vec<u8>>
123where
124    T: SchemaWrite<C, Src = T> + ?Sized,
125{
126    T::serialize(src, config)
127}
128
129/// Like [`crate::serialize_into`], but allows the caller to provide a custom configuration.
130///
131/// This has the same non-transactional, partial-write behavior documented by
132/// [`crate::serialize_into`].
133#[inline]
134pub fn serialize_into<T, C: Config>(dst: impl Writer, src: &T, config: C) -> WriteResult<()>
135where
136    T: SchemaWrite<C, Src = T> + ?Sized,
137{
138    T::serialize_into(dst, src, config)
139}
140
141/// Like [`crate::serialized_size`], but allows the caller to provide a custom configuration.
142#[inline]
143pub fn serialized_size<T, C: Config>(src: &T, config: C) -> WriteResult<u64>
144where
145    T: SchemaWrite<C, Src = T> + ?Sized,
146{
147    T::serialized_size(src, config)
148}
149
150/// Like [`crate::deserialize`], but allows the caller to provide a custom configuration.
151///
152/// # Examples
153///
154/// ```
155/// # #[cfg(feature = "alloc")] {
156/// # use wincode::{config::Configuration, len::FixIntLen};
157/// let config = Configuration::default().with_length_encoding::<FixIntLen<u32>>();
158/// let vec: Vec<u8> = vec![1, 2, 3];
159/// let bytes = wincode::config::serialize(&vec, config).unwrap();
160/// let deserialized: Vec<u8> = wincode::config::deserialize(&bytes, config).unwrap();
161/// assert_eq!(vec.len(), u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as usize);
162/// assert_eq!(vec, deserialized);
163/// # }
164/// ```
165#[inline(always)]
166pub fn deserialize<'de, T, C: Config>(src: &'de [u8], config: C) -> ReadResult<T>
167where
168    T: SchemaRead<'de, C, Dst = T>,
169{
170    T::deserialize(src, config)
171}
172
173/// Like [`crate::deserialize_exact`], but with a custom configuration.
174///
175/// # Examples
176///
177/// ```
178/// # #[cfg(feature = "alloc")] {
179/// # use wincode::config::Configuration;
180/// let config = Configuration::default();
181/// let bytes = wincode::config::serialize(&123u64, config).unwrap();
182/// let value: u64 = wincode::config::deserialize_exact(&bytes, config).unwrap();
183/// assert_eq!(value, 123);
184///
185/// let mut extra = bytes.clone();
186/// extra.push(0xAA);
187/// assert!(wincode::config::deserialize_exact::<u64, _>(&extra, config).is_err());
188/// # }
189/// ```
190#[inline(always)]
191#[expect(unused_variables)]
192pub fn deserialize_exact<'de, T, C: Config>(mut src: &'de [u8], config: C) -> ReadResult<T>
193where
194    T: SchemaRead<'de, C, Dst = T>,
195{
196    let value = T::get(src.by_ref())?;
197    if src.is_empty() {
198        Ok(value)
199    } else {
200        Err(error::trailing_bytes())
201    }
202}
203
204/// Like [`crate::deserialize_with_context`], but allows the caller to provide a custom configuration.
205#[inline(always)]
206#[expect(unused_variables)]
207pub fn deserialize_with_context<'de, Ctx, T, C: Config>(
208    ctx: Ctx,
209    src: &'de [u8],
210    config: C,
211) -> ReadResult<T>
212where
213    T: SchemaReadContext<'de, C, Ctx, Dst = T>,
214{
215    T::get_with_context(ctx, src)
216}
217
218/// Like [`crate::deserialize_mut`], but allows the caller to provide a custom configuration.
219#[inline(always)]
220#[expect(unused_variables)]
221pub fn deserialize_mut<'de, T, C: Config>(src: &'de mut [u8], config: C) -> ReadResult<T>
222where
223    T: SchemaRead<'de, C, Dst = T>,
224{
225    T::get(src)
226}
227
228/// Like [`crate::deserialize_from`], but allows the caller to provide a custom configuration.
229#[inline(always)]
230#[expect(unused_variables)]
231pub fn deserialize_from<'de, T, C: Config>(src: impl Reader<'de>, config: C) -> ReadResult<T>
232where
233    T: SchemaReadOwned<C, Dst = T>,
234{
235    T::deserialize_from(src)
236}
237
238/// Marker trait for types that can be deserialized via direct borrows from a [`Reader`].
239///
240/// <div class="warning">
241/// You should not manually implement this trait for your own type unless you absolutely
242/// know what you're doing. The derive macros will automatically implement this trait for your type
243/// if it is eligible for zero-copy deserialization.
244/// </div>
245///
246/// # Safety
247///
248/// - The type must not have any invalid bit patterns, no layout requirements, no endianness checks, etc.
249pub unsafe trait ZeroCopy<C: ConfigCore>: 'static {
250    /// Like [`crate::ZeroCopy::from_bytes`], but allows the caller to provide a custom configuration.
251    #[inline(always)]
252    #[expect(unused_variables)]
253    fn from_bytes<'de>(bytes: &'de [u8], config: C) -> ReadResult<&'de Self>
254    where
255        Self: SchemaRead<'de, C, Dst = Self> + Sized,
256    {
257        <&Self as SchemaRead<'de, C>>::get(bytes)
258    }
259
260    /// Like [`crate::ZeroCopy::from_bytes_mut`], but allows the caller to provide a custom configuration.
261    #[inline(always)]
262    #[expect(unused_variables)]
263    fn from_bytes_mut<'de>(bytes: &'de mut [u8], config: C) -> ReadResult<&'de mut Self>
264    where
265        Self: SchemaRead<'de, C, Dst = Self> + Sized,
266    {
267        <&mut Self as SchemaRead<'de, C>>::get(bytes)
268    }
269}