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}