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    #[inline]
33    #[expect(unused_variables)]
34    fn serialize_into(mut dst: impl Writer, src: &Self::Src, config: C) -> WriteResult<()> {
35        Self::write(dst.by_ref(), src)?;
36        dst.finish()?;
37        Ok(())
38    }
39
40    /// Get the size in bytes of the type when serialized.
41    #[inline]
42    #[expect(unused_variables)]
43    fn serialized_size(src: &Self::Src, config: C) -> WriteResult<u64> {
44        Self::size_of(src).map(|size| size as u64)
45    }
46}
47
48impl<T, C: Config> Serialize<C> for T where T: SchemaWrite<C> + ?Sized {}
49
50/// Like [`crate::Deserialize`], but allows the caller to provide a custom configuration.
51pub trait Deserialize<'de, C: Config>: SchemaRead<'de, C> {
52    /// Deserialize the input bytes into a new `Self::Dst`.
53    #[inline(always)]
54    #[expect(unused_variables)]
55    fn deserialize(src: &'de [u8], config: C) -> ReadResult<Self::Dst> {
56        Self::get(src)
57    }
58
59    /// Deserialize the input bytes into `dst`.
60    #[inline]
61    #[expect(unused_variables)]
62    fn deserialize_into(
63        src: &'de [u8],
64        dst: &mut MaybeUninit<Self::Dst>,
65        config: C,
66    ) -> ReadResult<()> {
67        Self::read(src, dst)
68    }
69}
70
71impl<'de, T, C: Config> Deserialize<'de, C> for T where T: SchemaRead<'de, C> {}
72
73/// Like [`crate::DeserializeOwned`], but allows the caller to provide a custom configuration.
74pub trait DeserializeOwned<C: Config>: SchemaReadOwned<C> {
75    /// Deserialize from the given [`Reader`] into a new `Self::Dst`.
76    #[inline(always)]
77    fn deserialize_from<'de>(
78        src: impl Reader<'de>,
79    ) -> ReadResult<<Self as SchemaRead<'de, C>>::Dst> {
80        Self::get(src)
81    }
82
83    /// Deserialize from the given [`Reader`] into `dst`.
84    #[inline]
85    fn deserialize_from_into<'de>(
86        src: impl Reader<'de>,
87        dst: &mut MaybeUninit<<Self as SchemaRead<'de, C>>::Dst>,
88    ) -> ReadResult<()> {
89        Self::read(src, dst)
90    }
91}
92
93impl<T, C: Config> DeserializeOwned<C> for T where T: SchemaReadOwned<C> {}
94
95/// Like [`crate::serialize`], but allows the caller to provide a custom configuration.
96///
97/// # Examples
98///
99/// ```
100/// # #[cfg(feature = "alloc")] {
101/// # use wincode::{config::Configuration, len::FixIntLen};
102/// let config = Configuration::default().with_length_encoding::<FixIntLen<u32>>();
103/// let vec: Vec<u8> = vec![1, 2, 3];
104/// let bytes = wincode::config::serialize(&vec, config).unwrap();
105/// assert_eq!(vec.len(), u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as usize);
106/// # }
107/// ```
108#[cfg(feature = "alloc")]
109pub fn serialize<T, C: Config>(src: &T, config: C) -> WriteResult<Vec<u8>>
110where
111    T: SchemaWrite<C, Src = T> + ?Sized,
112{
113    T::serialize(src, config)
114}
115
116/// Like [`crate::serialize_into`], but allows the caller to provide a custom configuration.
117#[inline]
118pub fn serialize_into<T, C: Config>(dst: impl Writer, src: &T, config: C) -> WriteResult<()>
119where
120    T: SchemaWrite<C, Src = T> + ?Sized,
121{
122    T::serialize_into(dst, src, config)
123}
124
125/// Like [`crate::serialized_size`], but allows the caller to provide a custom configuration.
126#[inline]
127pub fn serialized_size<T, C: Config>(src: &T, config: C) -> WriteResult<u64>
128where
129    T: SchemaWrite<C, Src = T> + ?Sized,
130{
131    T::serialized_size(src, config)
132}
133
134/// Like [`crate::deserialize`], but allows the caller to provide a custom configuration.
135///
136/// # Examples
137///
138/// ```
139/// # #[cfg(feature = "alloc")] {
140/// # use wincode::{config::Configuration, len::FixIntLen};
141/// let config = Configuration::default().with_length_encoding::<FixIntLen<u32>>();
142/// let vec: Vec<u8> = vec![1, 2, 3];
143/// let bytes = wincode::config::serialize(&vec, config).unwrap();
144/// let deserialized: Vec<u8> = wincode::config::deserialize(&bytes, config).unwrap();
145/// assert_eq!(vec.len(), u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as usize);
146/// assert_eq!(vec, deserialized);
147/// # }
148/// ```
149#[inline(always)]
150pub fn deserialize<'de, T, C: Config>(src: &'de [u8], config: C) -> ReadResult<T>
151where
152    T: SchemaRead<'de, C, Dst = T>,
153{
154    T::deserialize(src, config)
155}
156
157/// Like [`crate::deserialize_exact`], but with a custom configuration.
158///
159/// # Examples
160///
161/// ```
162/// # #[cfg(feature = "alloc")] {
163/// # use wincode::config::Configuration;
164/// let config = Configuration::default();
165/// let bytes = wincode::config::serialize(&123u64, config).unwrap();
166/// let value: u64 = wincode::config::deserialize_exact(&bytes, config).unwrap();
167/// assert_eq!(value, 123);
168///
169/// let mut extra = bytes.clone();
170/// extra.push(0xAA);
171/// assert!(wincode::config::deserialize_exact::<u64, _>(&extra, config).is_err());
172/// # }
173/// ```
174#[inline(always)]
175#[expect(unused_variables)]
176pub fn deserialize_exact<'de, T, C: Config>(mut src: &'de [u8], config: C) -> ReadResult<T>
177where
178    T: SchemaRead<'de, C, Dst = T>,
179{
180    let value = T::get(src.by_ref())?;
181    if src.is_empty() {
182        Ok(value)
183    } else {
184        Err(error::trailing_bytes())
185    }
186}
187
188/// Like [`crate::deserialize_with_context`], but allows the caller to provide a custom configuration.
189#[inline(always)]
190#[expect(unused_variables)]
191pub fn deserialize_with_context<'de, Ctx, T, C: Config>(
192    ctx: Ctx,
193    src: &'de [u8],
194    config: C,
195) -> ReadResult<T>
196where
197    T: SchemaReadContext<'de, C, Ctx, Dst = T>,
198{
199    T::get_with_context(ctx, src)
200}
201
202/// Like [`crate::deserialize_mut`], but allows the caller to provide a custom configuration.
203#[inline(always)]
204#[expect(unused_variables)]
205pub fn deserialize_mut<'de, T, C: Config>(src: &'de mut [u8], config: C) -> ReadResult<T>
206where
207    T: SchemaRead<'de, C, Dst = T>,
208{
209    T::get(src)
210}
211
212/// Like [`crate::deserialize_from`], but allows the caller to provide a custom configuration.
213#[inline(always)]
214#[expect(unused_variables)]
215pub fn deserialize_from<'de, T, C: Config>(src: impl Reader<'de>, config: C) -> ReadResult<T>
216where
217    T: SchemaReadOwned<C, Dst = T>,
218{
219    T::deserialize_from(src)
220}
221
222/// Marker trait for types that can be deserialized via direct borrows from a [`Reader`].
223///
224/// <div class="warning">
225/// You should not manually implement this trait for your own type unless you absolutely
226/// know what you're doing. The derive macros will automatically implement this trait for your type
227/// if it is eligible for zero-copy deserialization.
228/// </div>
229///
230/// # Safety
231///
232/// - The type must not have any invalid bit patterns, no layout requirements, no endianness checks, etc.
233pub unsafe trait ZeroCopy<C: ConfigCore>: 'static {
234    /// Like [`crate::ZeroCopy::from_bytes`], but allows the caller to provide a custom configuration.
235    #[inline(always)]
236    #[expect(unused_variables)]
237    fn from_bytes<'de>(bytes: &'de [u8], config: C) -> ReadResult<&'de Self>
238    where
239        Self: SchemaRead<'de, C, Dst = Self> + Sized,
240    {
241        <&Self as SchemaRead<'de, C>>::get(bytes)
242    }
243
244    /// Like [`crate::ZeroCopy::from_bytes_mut`], but allows the caller to provide a custom configuration.
245    #[inline(always)]
246    #[expect(unused_variables)]
247    fn from_bytes_mut<'de>(bytes: &'de mut [u8], config: C) -> ReadResult<&'de mut Self>
248    where
249        Self: SchemaRead<'de, C, Dst = Self> + Sized,
250    {
251        <&mut Self as SchemaRead<'de, C>>::get(bytes)
252    }
253}