serde_with/ser/mod.rs
1//! Module for [`SerializeAs`][] implementations
2//!
3//! The module contains the [`SerializeAs`][] trait and helper code.
4//! Additionally, it contains implementations of [`SerializeAs`][] for types defined in the Rust Standard Library or this crate.
5//!
6//! You can find more details on how to implement this trait for your types in the documentation of the [`SerializeAs`][] trait and details about the usage in the [user guide][].
7//!
8//! [user guide]: crate::guide
9
10#[cfg(feature = "alloc")]
11mod duplicates;
12mod impls;
13#[cfg(feature = "alloc")]
14mod skip_error;
15
16use crate::prelude::*;
17
18/// A **data structure** that can be serialized into any data format supported by Serde, analogue to [`Serialize`].
19///
20/// The trait is analogue to the [`serde::Serialize`][`Serialize`] trait, with the same meaning of input and output arguments.
21/// It can and should be implemented using the same code structure as the [`Serialize`] trait.
22/// As such, the same advice for [implementing `Serialize`][impl-serialize] applies here.
23///
24/// # Differences to [`Serialize`]
25///
26/// The trait is only required for container-like types or types implementing specific conversion functions.
27/// Container-like types are [`Vec`], [`BTreeMap`], but also [`Option`] and [`Box`].
28/// Conversion types serialize into a different serde data type.
29/// For example, [`DisplayFromStr`] uses the [`Display`] trait to serialize a String and [`DurationSeconds`] converts a [`Duration`] into either String or integer values.
30///
31/// This code shows how to implement [`Serialize`] for [`Box`]:
32///
33/// ```rust,ignore
34/// impl<T> Serialize for Box<T>
35/// where
36/// T: Serialize,
37/// {
38/// #[inline]
39/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
40/// where
41/// S: Serializer,
42/// {
43/// (**self).serialize(serializer)
44/// }
45/// }
46/// ```
47///
48/// and this code shows how to do the same using [`SerializeAs`][]:
49///
50/// ```rust,ignore
51/// impl<T, U> SerializeAs<Box<T>> for Box<U>
52/// where
53/// U: SerializeAs<T>,
54/// {
55/// fn serialize_as<S>(source: &Box<T>, serializer: S) -> Result<S::Ok, S::Error>
56/// where
57/// S: Serializer,
58/// {
59/// SerializeAsWrap::<T, U>::new(source).serialize(serializer)
60/// }
61/// }
62/// ```
63///
64/// It uses two type parameters, `T` and `U` instead of only one and performs the serialization step using the `SerializeAsWrap` type.
65/// The `T` type is the type on the Rust side before serialization, whereas the `U` type determines how the value will be serialized.
66/// These two changes are usually enough to make a container type implement [`SerializeAs`][].
67///
68/// [`SerializeAsWrap`] is a piece of glue code which turns [`SerializeAs`] into a serde compatible datatype, by converting all calls to `serialize` into `serialize_as`.
69/// This allows us to implement [`SerializeAs`] such that it can be applied recursively throughout the whole data structure.
70/// This is mostly important for container types, such as `Vec` or `BTreeMap`.
71/// In a `BTreeMap` this allows us to specify two different serialization behaviors, one for key and one for value, using the [`SerializeAs`] trait.
72///
73/// ## Implementing a converter Type
74///
75/// This shows a simplified implementation for [`DisplayFromStr`].
76///
77/// ```rust
78/// # #[cfg(feature = "macros")] {
79/// # use serde_with::{serde_as, SerializeAs};
80/// # use std::fmt::Display;
81/// struct DisplayFromStr;
82///
83/// impl<T> SerializeAs<T> for DisplayFromStr
84/// where
85/// T: Display,
86/// {
87/// fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
88/// where
89/// S: serde::Serializer,
90/// {
91/// serializer.collect_str(&source)
92/// }
93/// }
94/// #
95/// # #[serde_as]
96/// # #[derive(serde::Serialize)]
97/// # struct S (#[serde_as(as = "DisplayFromStr")] bool);
98/// #
99/// # assert_eq!(r#""false""#, serde_json::to_string(&S(false)).unwrap());
100/// # }
101/// ```
102///
103/// [`Box`]: std::boxed::Box
104/// [`BTreeMap`]: std::collections::BTreeMap
105/// [`Display`]: std::fmt::Display
106/// [`Duration`]: std::time::Duration
107/// [`Vec`]: std::vec::Vec
108/// [impl-serialize]: https://serde.rs/impl-serialize.html
109pub trait SerializeAs<T: ?Sized> {
110 /// Serialize this value into the given Serde serializer.
111 fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
112 where
113 S: Serializer;
114}
115
116/// Helper type to implement [`SerializeAs`] for container-like types.
117pub struct SerializeAsWrap<'a, T: ?Sized, U: ?Sized> {
118 value: &'a T,
119 marker: PhantomData<U>,
120}
121
122impl<'a, T, U> SerializeAsWrap<'a, T, U>
123where
124 T: ?Sized,
125 U: ?Sized,
126{
127 /// Create new instance with provided value.
128 pub fn new(value: &'a T) -> Self {
129 Self {
130 value,
131 marker: PhantomData,
132 }
133 }
134}
135
136impl<T, U> Serialize for SerializeAsWrap<'_, T, U>
137where
138 T: ?Sized,
139 U: ?Sized,
140 U: SerializeAs<T>,
141{
142 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
143 where
144 S: Serializer,
145 {
146 U::serialize_as(self.value, serializer)
147 }
148}
149
150impl<'a, T, U> From<&'a T> for SerializeAsWrap<'a, T, U>
151where
152 T: ?Sized,
153 U: ?Sized,
154 U: SerializeAs<T>,
155{
156 fn from(value: &'a T) -> Self {
157 Self::new(value)
158 }
159}
160
161impl<T: ?Sized> As<T> {
162 /// Serialize type `T` using [`SerializeAs`][]
163 ///
164 /// The function signature is compatible with [serde's `with` annotation][with-annotation].
165 ///
166 /// [with-annotation]: https://serde.rs/field-attrs.html#with
167 pub fn serialize<S, I>(value: &I, serializer: S) -> Result<S::Ok, S::Error>
168 where
169 S: Serializer,
170 T: SerializeAs<I>,
171 I: ?Sized,
172 {
173 T::serialize_as(value, serializer)
174 }
175}