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