bincode/features/serde/
mod.rs

1//! Support for serde integration. Enable this with the `serde` feature.
2//!
3//! To encode/decode type that implement serde's trait, you can use:
4//! - [borrow_decode_from_slice]
5//! - [decode_from_slice]
6//! - [encode_into_slice]
7//! - [encode_to_vec]
8//!
9//! For interop with bincode's [Decode]/[Encode], you can use:
10//! - [Compat]
11//! - [BorrowCompat]
12//!
13//! For interop with bincode's `derive` feature, you can use the `#[bincode(with_serde)]` attribute on each field that implements serde's traits.
14//!
15//! ```
16//! # #[cfg(feature = "derive")]
17//! # mod foo {
18//! # use bincode::{Decode, Encode};
19//! # use serde_derive::{Deserialize, Serialize};
20//! #[derive(Serialize, Deserialize)]
21//! pub struct SerdeType {
22//!     // ...
23//! }
24//!
25//! #[derive(Decode, Encode)]
26//! pub struct StructWithSerde {
27//!     #[bincode(with_serde)]
28//!     pub serde: SerdeType,
29//! }
30//!
31//! #[derive(Decode, Encode)]
32//! pub enum EnumWithSerde {
33//!     Unit(#[bincode(with_serde)] SerdeType),
34//!     Struct {
35//!         #[bincode(with_serde)]
36//!         serde: SerdeType,
37//!     },
38//! }
39//! # }
40//! ```
41//!
42//! # Known issues
43//!
44//! Because bincode is a format without meta data, there are several known issues with serde's attributes. Please do not use any of the following attributes if you plan on using bincode, or use bincode's own `derive` macros.
45//! - `#[serde(flatten)]`
46//! - `#[serde(skip)]`
47//! - `#[serde(skip_deserializing)]`
48//! - `#[serde(skip_serializing)]`
49//! - `#[serde(skip_serializing_if = "path")]`
50//! - `#[serde(tag = "...")]`
51//! - `#[serde(untagged)]`
52//!
53//! **Using any of the above attributes can and will cause issues with bincode and will result in lost data**. Consider using bincode's own derive macro instead.
54//!
55//! # Why move away from serde?
56//!
57//! Serde is a great library, but it has some issues that makes us want to be decoupled from serde:
58//! - The issues documented above with attributes.
59//! - Serde has chosen to not have a MSRV ([source](https://github.com/serde-rs/serde/pull/2257)). We think MSRV is important, bincode 1 still compiles with rust 1.18.
60//! - Before serde we had rustc-serializer. Serde has more than replaced rustc-serializer, but we can imagine a future where serde is replaced by something else.
61//! - We believe that less dependencies is better, and that you should be able to choose your own dependencies. If you disable all features, bincode 2 only has 1 dependency. ([`unty`], a micro crate we manage ourselves)
62//!
63//! **note:** just because we're making serde an optional dependency, it does not mean we're dropping support for serde. Serde will still be fully supported, we're just giving you the option to not use it.
64//!
65//! [Decode]: ../de/trait.Decode.html
66//! [Encode]: ../enc/trait.Encode.html
67//! [`unty`]: https://crates.io/crates/unty
68
69mod de_borrowed;
70mod de_owned;
71mod ser;
72
73pub use self::de_borrowed::*;
74pub use self::de_owned::*;
75pub use self::ser::*;
76
77/// A serde-specific error that occurred while decoding.
78#[derive(Debug)]
79#[non_exhaustive]
80pub enum DecodeError {
81    /// Bincode does not support serde's `any` decoding feature.
82    ///
83    /// See the "known issues" list in the serde module for more information on this.
84    AnyNotSupported,
85
86    /// Bincode does not support serde identifiers
87    IdentifierNotSupported,
88
89    /// Bincode does not support serde's `ignored_any`.
90    ///
91    /// See the "known issues" list in the serde module for more information on this.
92    IgnoredAnyNotSupported,
93
94    /// Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead
95    CannotBorrowOwnedData,
96
97    /// Could not allocate data like `String` and `Vec<u8>`
98    #[cfg(not(feature = "alloc"))]
99    CannotAllocate,
100
101    /// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
102    #[cfg(not(feature = "alloc"))]
103    CustomError,
104}
105
106#[cfg(feature = "alloc")]
107impl serde::de::Error for crate::error::DecodeError {
108    fn custom<T>(msg: T) -> Self
109    where
110        T: core::fmt::Display,
111    {
112        use alloc::string::ToString;
113        Self::OtherString(msg.to_string())
114    }
115}
116
117#[cfg(not(feature = "std"))]
118impl serde::de::StdError for crate::error::DecodeError {}
119
120#[cfg(not(feature = "alloc"))]
121impl serde::de::Error for crate::error::DecodeError {
122    fn custom<T>(_: T) -> Self
123    where
124        T: core::fmt::Display,
125    {
126        DecodeError::CustomError.into()
127    }
128}
129
130#[allow(clippy::from_over_into)]
131impl Into<crate::error::DecodeError> for DecodeError {
132    fn into(self) -> crate::error::DecodeError {
133        crate::error::DecodeError::Serde(self)
134    }
135}
136
137/// A serde-specific error that occurred while encoding.
138#[derive(Debug)]
139#[non_exhaustive]
140pub enum EncodeError {
141    /// Serde provided bincode with a sequence without a length, which is not supported in bincode
142    SequenceMustHaveLength,
143
144    /// [Serializer::collect_str] got called but bincode was unable to allocate memory.
145    #[cfg(not(feature = "alloc"))]
146    CannotCollectStr,
147
148    /// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
149    #[cfg(not(feature = "alloc"))]
150    CustomError,
151}
152
153#[allow(clippy::from_over_into)]
154impl Into<crate::error::EncodeError> for EncodeError {
155    fn into(self) -> crate::error::EncodeError {
156        crate::error::EncodeError::Serde(self)
157    }
158}
159
160#[cfg(feature = "alloc")]
161impl serde::ser::Error for crate::error::EncodeError {
162    fn custom<T>(msg: T) -> Self
163    where
164        T: core::fmt::Display,
165    {
166        use alloc::string::ToString;
167
168        Self::OtherString(msg.to_string())
169    }
170}
171
172#[cfg(not(feature = "std"))]
173impl serde::de::StdError for crate::error::EncodeError {}
174
175#[cfg(not(feature = "alloc"))]
176impl serde::ser::Error for crate::error::EncodeError {
177    fn custom<T>(_: T) -> Self
178    where
179        T: core::fmt::Display,
180    {
181        EncodeError::CustomError.into()
182    }
183}
184
185/// Wrapper struct that implements [Decode] and [Encode] on any type that implements serde's [DeserializeOwned] and [Serialize] respectively.
186///
187/// This works for most types, but if you're dealing with borrowed data consider using [BorrowCompat] instead.
188///
189/// [Decode]: ../de/trait.Decode.html
190/// [Encode]: ../enc/trait.Encode.html
191/// [DeserializeOwned]: https://docs.rs/serde/1/serde/de/trait.DeserializeOwned.html
192/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
193#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
194pub struct Compat<T>(pub T);
195
196impl<Context, T> crate::Decode<Context> for Compat<T>
197where
198    T: serde::de::DeserializeOwned,
199{
200    fn decode<D: crate::de::Decoder>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
201        let serde_decoder = de_owned::SerdeDecoder { de: decoder };
202        T::deserialize(serde_decoder).map(Compat)
203    }
204}
205impl<'de, T, Context> crate::BorrowDecode<'de, Context> for Compat<T>
206where
207    T: serde::de::DeserializeOwned,
208{
209    fn borrow_decode<D: crate::de::BorrowDecoder<'de>>(
210        decoder: &mut D,
211    ) -> Result<Self, crate::error::DecodeError> {
212        let serde_decoder = de_owned::SerdeDecoder { de: decoder };
213        T::deserialize(serde_decoder).map(Compat)
214    }
215}
216
217impl<T> crate::Encode for Compat<T>
218where
219    T: serde::Serialize,
220{
221    fn encode<E: crate::enc::Encoder>(
222        &self,
223        encoder: &mut E,
224    ) -> Result<(), crate::error::EncodeError> {
225        let serializer = ser::SerdeEncoder { enc: encoder };
226        self.0.serialize(serializer)?;
227        Ok(())
228    }
229}
230
231impl<T> core::fmt::Debug for Compat<T>
232where
233    T: core::fmt::Debug,
234{
235    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
236        f.debug_tuple("Compat").field(&self.0).finish()
237    }
238}
239
240impl<T> core::fmt::Display for Compat<T>
241where
242    T: core::fmt::Display,
243{
244    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
245        self.0.fmt(f)
246    }
247}
248
249/// Wrapper struct that implements [BorrowDecode] and [Encode] on any type that implements serde's [Deserialize] and [Serialize] respectively. This is mostly used on `&[u8]` and `&str`, for other types consider using [Compat] instead.
250///
251/// [BorrowDecode]: ../de/trait.BorrowDecode.html
252/// [Encode]: ../enc/trait.Encode.html
253/// [Deserialize]: https://docs.rs/serde/1/serde/de/trait.Deserialize.html
254/// [Serialize]: https://docs.rs/serde/1/serde/trait.Serialize.html
255#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
256pub struct BorrowCompat<T>(pub T);
257
258impl<'de, T, Context> crate::de::BorrowDecode<'de, Context> for BorrowCompat<T>
259where
260    T: serde::de::Deserialize<'de>,
261{
262    fn borrow_decode<D: crate::de::BorrowDecoder<'de>>(
263        decoder: &mut D,
264    ) -> Result<Self, crate::error::DecodeError> {
265        let serde_decoder = de_borrowed::SerdeDecoder {
266            de: decoder,
267            pd: core::marker::PhantomData,
268        };
269        T::deserialize(serde_decoder).map(BorrowCompat)
270    }
271}
272
273impl<T> crate::Encode for BorrowCompat<T>
274where
275    T: serde::Serialize,
276{
277    fn encode<E: crate::enc::Encoder>(
278        &self,
279        encoder: &mut E,
280    ) -> Result<(), crate::error::EncodeError> {
281        let serializer = ser::SerdeEncoder { enc: encoder };
282        self.0.serialize(serializer)?;
283        Ok(())
284    }
285}
286
287impl<T> core::fmt::Debug for BorrowCompat<T>
288where
289    T: core::fmt::Debug,
290{
291    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
292        f.debug_tuple("BorrowCompat").field(&self.0).finish()
293    }
294}
295
296impl<T> core::fmt::Display for BorrowCompat<T>
297where
298    T: core::fmt::Display,
299{
300    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
301        self.0.fmt(f)
302    }
303}