serdapt/
lib.rs

1// Copyright (c) 2024 Stephane Raux. Distributed under the 0BSD license.
2
3//! # Overview
4//! - [📦 crates.io](https://crates.io/crates/serdapt)
5//! - [📖 Documentation](https://docs.rs/serdapt)
6//! - [âš– 0BSD license](https://spdx.org/licenses/0BSD.html)
7//!
8//! Tools to build composable adapters for `#[serde(with = ...)]`.
9//!
10//! `serde` allows customizing how fields are serialized when deriving `Serialize` and `Deserialize`
11//! thanks to the `#[serde(with = "path")]` attribute. With such an attribute, `path::serialize`
12//! and `path::deserialize` are the functions used for serialization. By using a type for `path`,
13//! composable serialization adapters can be defined, e.g. to customize how items in a container
14//! are serialized.
15//!
16//! These adapters can also simplify implementing `Serialize` and `Deserialize`.
17//!
18//! # Apply adapter
19//! An adapter is applied by specifying the adapter path in `#[serde(with = "...")]`. The path
20//! needs to be suitable as a prefix for functions, i.e. `path::serialize` and `path::deserialize`.
21//! This means the turbofish is needed for generic adapters, e.g. `Outer::<Inner>`.
22//!
23//! ## Example
24//! ```
25//! use serde::{Deserialize, Serialize};
26//!
27//! #[derive(Debug, Deserialize, PartialEq, Serialize)]
28//! struct Foo {
29//!     #[serde(with = "serdapt::Seq::<serdapt::Str>")]
30//!     xs: Vec<i32>,
31//! }
32//!
33//! let foo = Foo { xs: vec![3, 4] };
34//! let v = serde_json::to_value(&foo).unwrap();
35//! assert_eq!(v, serde_json::json!({ "xs": ["3", "4"] }));
36//! assert_eq!(serde_json::from_value::<Foo>(v).unwrap(), foo);
37//! ```
38//!
39//! # Define serialization adapter
40//! 1. Define a type to represent the new adapter.
41//! 1. Implement [`SerializeWith`] and [`DeserializeWith`] for this type. This allows adapter
42//!    composability.
43//! 1. Define `serialize` and `deserialize` inherent functions for this type, delegating to
44//!    [`SerializeWith`] and [`DeserializeWith`] respectively. These are the functions the
45//!    serde-generated code calls.
46//!
47//! ## Simple adapter example
48//! ```
49//! use serdapt::{DeserializeWith, SerializeWith};
50//! use serde::{Deserialize, Deserializer, Serialize, Serializer};
51//! use serde_json::json;
52//!
53//! #[derive(Deserialize, Serialize)]
54//! struct Point {
55//!     x: i32,
56//!     y: i32,
57//! }
58//!
59//! struct Coords;
60//!
61//! impl Coords {
62//!     fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
63//!     where
64//!         T: ?Sized,
65//!         S: Serializer,
66//!         Self: SerializeWith<T>,
67//!     {
68//!         Self::serialize_with(value, serializer)
69//!     }
70//!
71//!     fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
72//!     where
73//!         D: Deserializer<'de>,
74//!         Self: DeserializeWith<'de, T>,
75//!     {
76//!         Self::deserialize_with(deserializer)
77//!     }
78//! }
79//!
80//! impl SerializeWith<(i32, i32)> for Coords {
81//!     fn serialize_with<S>(&(x, y): &(i32, i32), serializer: S) -> Result<S::Ok, S::Error>
82//!     where
83//!         S: Serializer,
84//!     {
85//!         Serialize::serialize(&Point { x, y }, serializer)
86//!     }
87//! }
88//!
89//! impl<'de> DeserializeWith<'de, (i32, i32)> for Coords {
90//!     fn deserialize_with<D>(deserializer: D) -> Result<(i32, i32), D::Error>
91//!     where
92//!         D: Deserializer<'de>,
93//!     {
94//!         let Point { x, y } = Deserialize::deserialize(deserializer)?;
95//!         Ok((x, y))
96//!     }
97//! }
98//!
99//! #[derive(Debug, Deserialize, PartialEq, Serialize)]
100//! struct Shape(#[serde(with = "serdapt::Seq::<Coords>")] Vec<(i32, i32)>);
101//!
102//! let original = Shape(vec![(1, 2), (3, 4)]);
103//! let serialized = serde_json::to_value(&original).unwrap();
104//! assert_eq!(serialized, json!([{ "x": 1, "y": 2 }, { "x": 3, "y": 4 }]));
105//! let deserialized = serde_json::from_value::<Shape>(serialized).unwrap();
106//! assert_eq!(deserialized, original);
107//! ```
108//!
109//! ## Generic adapter example
110//! ```
111//! use core::marker::PhantomData;
112//! use serdapt::{DeserializeWith, SerializeWith, WithEncoding};
113//! use serde::{Deserialize, Deserializer, Serialize, Serializer};
114//! use serde_json::json;
115//!
116//! #[derive(Debug, Deserialize, PartialEq, Serialize)]
117//! struct Point<T> {
118//!     x: T,
119//!     y: T,
120//! }
121//!
122//! struct Coords<F>(PhantomData<F>);
123//!
124//! impl<F> Coords<F> {
125//!     fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
126//!     where
127//!         T: ?Sized,
128//!         S: Serializer,
129//!         Self: SerializeWith<T>,
130//!     {
131//!         Self::serialize_with(value, serializer)
132//!     }
133//!
134//!     fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
135//!     where
136//!         D: Deserializer<'de>,
137//!         Self: DeserializeWith<'de, T>,
138//!     {
139//!         Self::deserialize_with(deserializer)
140//!     }
141//! }
142//!
143//! impl<F, T> SerializeWith<Point<T>> for Coords<F>
144//! where
145//!     F: SerializeWith<T>,
146//! {
147//!     fn serialize_with<S>(Point { x, y }: &Point<T>, serializer: S) -> Result<S::Ok, S::Error>
148//!     where
149//!         S: Serializer,
150//!     {
151//!         let p: Point<WithEncoding<&F, &T>> = Point {
152//!             x: x.into(),
153//!             y: y.into()
154//!         };
155//!         Serialize::serialize(&p, serializer)
156//!     }
157//! }
158//!
159//! impl<'de, F, T> DeserializeWith<'de, Point<T>> for Coords<F>
160//! where
161//!     F: DeserializeWith<'de, T>,
162//! {
163//!     fn deserialize_with<D>(deserializer: D) -> Result<Point<T>, D::Error>
164//!     where
165//!         D: Deserializer<'de>,
166//!     {
167//!         let p: Point<WithEncoding<F, T>> = Deserialize::deserialize(deserializer)?;
168//!         Ok(Point {
169//!             x: p.x.into_inner(),
170//!             y: p.y.into_inner(),
171//!         })
172//!     }
173//! }
174//!
175//! #[derive(Debug, Deserialize, PartialEq, Serialize)]
176//! struct Shape(
177//!     #[serde(with = "serdapt::Seq::<Coords<serdapt::Str>>")] Vec<Point<i32>>,
178//! );
179//!
180//! let original = Shape(vec![Point { x: 1, y: 2 }, Point { x: 3, y: 4 }]);
181//! let serialized = serde_json::to_value(&original).unwrap();
182//! assert_eq!(serialized, json!([{ "x": "1", "y": "2" }, { "x": "3", "y": "4" }]));
183//! let deserialized = serde_json::from_value::<Shape>(serialized).unwrap();
184//! assert_eq!(deserialized, original);
185//! ```
186//!
187//! # Related project
188//! [`serde_with`](https://crates.io/crates/serde_with) allows the same composability with the help
189//! of an additional proc-macro, though it is also possible to use `#[serde(with = ...)]` directly.
190//!
191//! Some key differences are:
192//! - `serdapt` is simpler and does not need any additional proc-macro, giving up on any ergonomics
193//!   such a macro provides.
194//! - It avoids a macro ordering issue that can lead to generated serialization code not using the
195//!   requested adapter despite a sucessful compilation.
196//! - It works seamlessly with conditional compilation.
197//! - It is limited to supporting types in the standard library, with support for third-party types
198//!   delegated to other crates, which solves dependency issues.
199//!
200//! # Contribute
201//! All contributions shall be licensed under the [0BSD license](https://spdx.org/licenses/0BSD.html).
202
203#![deny(missing_docs)]
204#![cfg_attr(not(feature = "std"), no_std)]
205
206#[cfg(feature = "alloc")]
207extern crate alloc;
208
209mod add_ref;
210mod array;
211mod bytes;
212mod cell;
213mod codec;
214mod convert;
215#[cfg(feature = "alloc")]
216mod cow;
217mod fold;
218mod from;
219mod human;
220mod identity;
221mod into;
222mod map;
223mod map_as_seq;
224#[cfg(feature = "std")]
225mod mutex;
226mod option;
227mod ptr;
228mod range;
229mod result;
230mod reverse;
231#[cfg(feature = "std")]
232mod rwlock;
233mod seq_as_map;
234mod sequence;
235mod str;
236mod try_from;
237mod try_into;
238mod wrapping;
239
240pub use add_ref::AddRef;
241pub use array::Array;
242#[cfg(feature = "alloc")]
243pub use bytes::ByteVec;
244pub use bytes::Bytes;
245pub use cell::Cell;
246pub use codec::Codec;
247pub use convert::{Convert, RefConvert, RefTryConvert, TryConvert};
248#[cfg(feature = "alloc")]
249pub use cow::Cow;
250pub use fold::Fold;
251pub use from::From;
252pub use human::HumanOr;
253pub use identity::Id;
254pub use into::Into;
255pub use map::Map;
256pub use map_as_seq::MapAsSeq;
257#[cfg(feature = "std")]
258pub use mutex::Mutex;
259pub use option::Option;
260pub use ptr::Ptr;
261pub use range::Range;
262pub use result::Result;
263pub use reverse::Reverse;
264#[cfg(feature = "std")]
265pub use rwlock::RwLock;
266pub use seq_as_map::SeqAsMap;
267pub use sequence::Seq;
268pub use str::Str;
269pub use try_from::TryFrom;
270pub use try_into::TryInto;
271pub use wrapping::Wrapping;
272
273use core::marker::PhantomData;
274use serde::{Deserialize, Deserializer, Serialize, Serializer};
275
276/// Trait for types that can be used as serialization adapters with `#[serde(with = ...)]`
277///
278/// This is the foundation to build composable serialization adapters.
279pub trait SerializeWith<T: ?Sized> {
280    /// Serializes `value` using `serializer`
281    fn serialize_with<S: Serializer>(
282        value: &T,
283        serializer: S,
284    ) -> core::result::Result<S::Ok, S::Error>;
285}
286
287/// Trait for types that can be used as deserialization adapters with `#[serde(with = ...)]`
288///
289/// This is the foundation to build composable deserialization adapters.
290pub trait DeserializeWith<'de, T> {
291    /// Deserializes a value using `deserializer`
292    fn deserialize_with<D>(deserializer: D) -> core::result::Result<T, D::Error>
293    where
294        D: Deserializer<'de>;
295}
296
297impl<F, T> SerializeWith<&T> for &F
298where
299    F: SerializeWith<T>,
300    T: ?Sized,
301{
302    fn serialize_with<S: Serializer>(
303        value: &&T,
304        serializer: S,
305    ) -> core::result::Result<S::Ok, S::Error> {
306        F::serialize_with(*value, serializer)
307    }
308}
309
310impl<F, T> SerializeWith<&mut T> for &F
311where
312    F: SerializeWith<T>,
313    T: ?Sized,
314{
315    fn serialize_with<S: Serializer>(
316        value: &&mut T,
317        serializer: S,
318    ) -> core::result::Result<S::Ok, S::Error> {
319        F::serialize_with(*value, serializer)
320    }
321}
322
323/// Type bundling a value and how to (de)serialize it
324///
325/// It allows a value to be (de)serialized with `serde` in a custom manner.
326pub struct WithEncoding<F, T: ?Sized> {
327    encoding: PhantomData<F>,
328    value: T,
329}
330
331impl<F, T> WithEncoding<F, T> {
332    /// Returns inner value
333    pub fn into_inner(self) -> T {
334        self.value
335    }
336}
337
338impl<F, T> core::convert::From<T> for WithEncoding<F, T> {
339    fn from(value: T) -> Self {
340        Self {
341            encoding: PhantomData,
342            value,
343        }
344    }
345}
346
347impl<F, T> Serialize for WithEncoding<F, T>
348where
349    F: SerializeWith<T>,
350    T: ?Sized,
351{
352    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
353    where
354        S: Serializer,
355    {
356        F::serialize_with(&self.value, serializer)
357    }
358}
359
360impl<'de, F, T> Deserialize<'de> for WithEncoding<F, T>
361where
362    F: DeserializeWith<'de, T>,
363{
364    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
365    where
366        D: Deserializer<'de>,
367    {
368        F::deserialize_with(deserializer).map(|x| x.into())
369    }
370}
371
372macro_rules! impl_tuple {
373    ($($types:ident $adapters:ident $xs:ident,)*) => {
374        impl<$($types, $adapters),*> SerializeWith<($($types,)*)> for ($($adapters,)*)
375        where
376            $($adapters: SerializeWith<$types>,)*
377        {
378            fn serialize_with<S: Serializer>(
379                value: &($($types,)*),
380                serializer: S,
381            ) -> core::result::Result<S::Ok, S::Error> {
382                let ($($xs,)*) = value;
383                Serialize::serialize(
384                    &($(WithEncoding::<&$adapters, _>::from($xs),)*),
385                    serializer,
386                )
387            }
388        }
389
390        impl<'de, $($types, $adapters),*> DeserializeWith<'de, ($($types,)*)> for ($($adapters,)*)
391        where
392            $($adapters: DeserializeWith<'de, $types>,)*
393        {
394            fn deserialize_with<D>(deserializer: D) -> core::result::Result<($($types,)*), D::Error>
395            where
396                D: Deserializer<'de>,
397            {
398                let ($($xs,)*) = <($(WithEncoding<$adapters, $types>,)*) as Deserialize>::deserialize(deserializer)?;
399                Ok(($($xs.value,)*))
400            }
401        }
402    };
403}
404
405macro_rules! impl_tuples {
406    (
407        $($tys:ident $adapters:ident $xs:ident,)*
408        @ $ty_head:ident $adapter_head:ident $x_head:ident, $($ty_tail:ident $adapter_tail:ident $x_tail:ident,)*
409    ) => {
410        impl_tuple!($($tys $adapters $xs,)*);
411        impl_tuples!($($tys $adapters $xs,)* $ty_head $adapter_head $x_head, @ $($ty_tail $adapter_tail $x_tail,)*);
412
413    };
414    ($($tys:ident $adapters:ident $xs:ident,)* @) => {
415        impl_tuple!($($tys $adapters $xs,)*);
416
417    };
418    ($($tys:ident $adapters:ident $xs:ident,)*) => {
419        impl_tuples!(@ $($tys $adapters $xs,)*);
420    };
421}
422
423impl_tuples!(
424    T0 A0 x0,
425    T1 A1 x1,
426    T2 A2 x2,
427    T3 A3 x3,
428    T4 A4 x4,
429    T5 A5 x5,
430    T6 A6 x6,
431    T7 A7 x7,
432    T8 A8 x8,
433    T9 A9 x9,
434    T10 A10 x10,
435    T11 A11 x11,
436    T12 A12 x12,
437    T13 A13 x13,
438    T14 A14 x14,
439    T15 A15 x15,
440);
441
442#[cfg(test)]
443mod test_utils {
444    use core::fmt::Debug;
445    use serde::{de::DeserializeOwned, Serialize};
446    use serde_json::Value;
447
448    #[track_caller]
449    pub(crate) fn check_serialization<T>(x: T, expected: Value)
450    where
451        T: PartialEq + Debug + Serialize + DeserializeOwned,
452    {
453        let actual = serde_json::to_value(&x).unwrap();
454        assert_eq!(actual, expected);
455        let deserialized = serde_json::from_value::<T>(actual).unwrap();
456        assert_eq!(x, deserialized);
457    }
458}