bincode_next/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_next::{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//! ### `deserialize_any` and Self-Describing Formats
56//!
57//! Bincode is not a self-describing format (it does not store type metadata with the data map like JSON does). Because of this, it **does not support `deserialize_any`**.
58//!
59//! This means that types like `serde_json::Value` or `toml::Value` cannot be deserialized directly from a bincode stream. Attempting to do so will result in an `AnyNotSupported` error. To work around this, you must deserialize into strongly-typed data structures representing your schema, rather than dynamic or nested value enums.
60//!
61//! # Why move away from serde?
62//!
63//! Serde is a great library, but it has some issues that makes us want to be decoupled from serde:
64//! - The issues documented above with attributes.
65//! - 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.
66//! - 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.
67//! - 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)
68//!
69//! **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.
70//!
71//! [Decode]: ../de/trait.Decode.html
72//! [Encode]: ../enc/trait.Encode.html
73//! [`unty`\]: <https://crates.io/crates/unty>
74
75mod de_borrowed;
76mod de_owned;
77mod ser;
78
79pub use self::de_borrowed::*;
80pub use self::de_owned::*;
81pub use self::ser::*;
82
83/// A serde-specific error that occurred while decoding.
84#[derive(Debug)]
85#[non_exhaustive]
86pub enum DecodeError {
87 /// Bincode does not support serde's `any` decoding feature.
88 ///
89 /// See the "known issues" list in the serde module for more information on this.
90 AnyNotSupported,
91
92 /// Bincode does not support serde identifiers
93 IdentifierNotSupported,
94
95 /// Bincode does not support serde's `ignored_any`.
96 ///
97 /// See the "known issues" list in the serde module for more information on this.
98 IgnoredAnyNotSupported,
99
100 /// Serde tried decoding a borrowed value from an owned reader. Use `serde_decode_borrowed_from_*` instead
101 CannotBorrowOwnedData,
102
103 /// Could not allocate data like `String` and `Vec<u8>`
104 #[cfg(not(feature = "alloc"))]
105 CannotAllocate,
106
107 /// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
108 #[cfg(not(feature = "alloc"))]
109 CustomError,
110}
111
112#[cfg(feature = "alloc")]
113impl serde::de::Error for crate::error::DecodeError {
114 fn custom<T>(msg: T) -> Self
115 where
116 T: core::fmt::Display,
117 {
118 use alloc::string::ToString;
119 crate::error::cold_decode_error_other_string::<()>(msg.to_string()).unwrap_err()
120 }
121}
122
123#[cfg(not(feature = "alloc"))]
124impl serde::de::Error for crate::error::DecodeError {
125 fn custom<T>(_: T) -> Self
126 where
127 T: core::fmt::Display,
128 {
129 crate::error::cold_decode_error_serde::<()>(DecodeError::CustomError).unwrap_err()
130 }
131}
132
133#[allow(clippy::from_over_into)]
134impl Into<crate::error::DecodeError> for DecodeError {
135 fn into(self) -> crate::error::DecodeError {
136 crate::error::cold_decode_error_serde::<()>(self).unwrap_err()
137 }
138}
139
140/// A serde-specific error that occurred while encoding.
141#[derive(Debug)]
142#[non_exhaustive]
143pub enum EncodeError {
144 /// Serde provided bincode with a sequence without a length, which is not supported in bincode
145 SequenceMustHaveLength,
146
147 /// [Serializer::collect_str] got called but bincode was unable to allocate memory.
148 #[cfg(not(feature = "alloc"))]
149 CannotCollectStr,
150
151 /// Custom serde error but bincode is unable to allocate a string. Set a breakpoint where this is thrown for more information.
152 #[cfg(not(feature = "alloc"))]
153 CustomError,
154}
155
156#[allow(clippy::from_over_into)]
157impl Into<crate::error::EncodeError> for EncodeError {
158 fn into(self) -> crate::error::EncodeError {
159 crate::error::cold_encode_error_serde::<()>(self).unwrap_err()
160 }
161}
162
163#[cfg(feature = "alloc")]
164impl serde::ser::Error for crate::error::EncodeError {
165 fn custom<T>(msg: T) -> Self
166 where
167 T: core::fmt::Display,
168 {
169 use alloc::string::ToString;
170
171 crate::error::cold_encode_error_other_string::<()>(msg.to_string()).unwrap_err()
172 }
173}
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 crate::error::cold_encode_error_serde::<()>(EncodeError::CustomError).unwrap_err()
182 }
183}
184
185/// Wrapper struct that implements [`crate::Decode`\] and [`crate::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(
236 &self,
237 f: &mut core::fmt::Formatter<'_>,
238 ) -> core::fmt::Result {
239 f.debug_tuple("Compat").field(&self.0).finish()
240 }
241}
242
243impl<T> core::fmt::Display for Compat<T>
244where
245 T: core::fmt::Display,
246{
247 fn fmt(
248 &self,
249 f: &mut core::fmt::Formatter<'_>,
250 ) -> core::fmt::Result {
251 self.0.fmt(f)
252 }
253}
254
255/// Wrapper struct that implements [`crate::de::BorrowDecode`\] and [`crate::Encode`\] on any type that implements serde's [`Deserialize`\] and [`Serialize`\] respectively.
256///
257/// This is mostly used on `&[u8]` and `&str`, for other types consider using [`Compat`\] instead.
258/// [`Deserialize`\]: <https://docs.rs/serde/1/serde/de/trait.Deserialize.html>
259/// [`Serialize`\]: <https://docs.rs/serde/1/serde/trait.Serialize.html>
260#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
261pub struct BorrowCompat<T>(pub T);
262
263impl<'de, T, Context> crate::de::BorrowDecode<'de, Context> for BorrowCompat<T>
264where
265 T: serde::de::Deserialize<'de>,
266{
267 fn borrow_decode<D: crate::de::BorrowDecoder<'de>>(
268 decoder: &mut D
269 ) -> Result<Self, crate::error::DecodeError> {
270 let serde_decoder = de_borrowed::SerdeDecoder {
271 de: decoder,
272 pd: core::marker::PhantomData,
273 };
274 T::deserialize(serde_decoder).map(BorrowCompat)
275 }
276}
277
278impl<T> crate::Encode for BorrowCompat<T>
279where
280 T: serde::Serialize,
281{
282 fn encode<E: crate::enc::Encoder>(
283 &self,
284 encoder: &mut E,
285 ) -> Result<(), crate::error::EncodeError> {
286 let serializer = ser::SerdeEncoder { enc: encoder };
287 self.0.serialize(serializer)?;
288 Ok(())
289 }
290}
291
292impl<T> core::fmt::Debug for BorrowCompat<T>
293where
294 T: core::fmt::Debug,
295{
296 fn fmt(
297 &self,
298 f: &mut core::fmt::Formatter<'_>,
299 ) -> core::fmt::Result {
300 f.debug_tuple("BorrowCompat").field(&self.0).finish()
301 }
302}
303
304impl<T> core::fmt::Display for BorrowCompat<T>
305where
306 T: core::fmt::Display,
307{
308 fn fmt(
309 &self,
310 f: &mut core::fmt::Formatter<'_>,
311 ) -> core::fmt::Result {
312 self.0.fmt(f)
313 }
314}