serde_with/serde_conv.rs
1/// Create new conversion adapters from functions
2///
3/// The macro lets you create a new converter, which is usable for serde's with-attribute and `#[serde_as]`.
4/// Its main use case is to write simple converters for types, which are not serializable.
5/// Another use-case is to change the serialization behavior if the implemented `Serialize`/`Deserialize` trait is insufficient.
6///
7/// The macro takes four arguments:
8///
9/// 1. The name of the converter type.
10/// The type can be prefixed with a visibility modifies like `pub` or `pub(crate)`.
11/// By default, the type is not marked as public (`pub(self)`).
12/// 2. The type `T` we want to extend with custom behavior.
13/// 3. A function or macro taking a `&T` and returning a serializable type.
14/// 4. A function or macro taking a deserializable type and returning a `Result<T, E>`.
15/// The error type `E` must implement [`Display`].
16///
17/// [`Display`]: std::fmt::Display
18///
19/// # Example
20///
21/// In this example, we write custom serialization behavior for a `Rgb` type.
22/// We want to serialize it as a `[u8; 3]`.
23///
24/// ```rust
25/// # #[cfg(feature = "macros")] {
26/// # use serde::{Serialize, Deserialize};
27/// # use serde_with::serde_as;
28///
29/// #[derive(Clone, Copy, Debug, PartialEq)]
30/// struct Rgb {
31/// red: u8,
32/// green: u8,
33/// blue: u8,
34/// }
35///
36/// serde_with::serde_conv!(
37/// RgbAsArray,
38/// Rgb,
39/// |rgb: &Rgb| [rgb.red, rgb.green, rgb.blue],
40/// |value: [u8; 3]| -> Result<_, std::convert::Infallible> {
41/// Ok(Rgb {
42/// red: value[0],
43/// green: value[1],
44/// blue: value[2],
45/// })
46/// }
47/// );
48///
49/// //////////////////////////////////////////////////
50///
51/// // We define some colors to be used later
52///
53/// let green = Rgb {red: 0, green: 255, blue: 0};
54/// let orange = Rgb {red: 255, green: 128, blue: 0};
55/// let pink = Rgb {red: 255, green: 0, blue: 255};
56///
57/// //////////////////////////////////////////////////
58///
59/// // We can now use the `RgbAsArray` adapter with `serde_as`.
60///
61/// #[serde_as]
62/// #[derive(Debug, PartialEq, Serialize, Deserialize)]
63/// struct Colors {
64/// #[serde_as(as = "RgbAsArray")]
65/// one_rgb: Rgb,
66/// #[serde_as(as = "Vec<RgbAsArray>")]
67/// rgbs_in_vec: Vec<Rgb>,
68/// }
69///
70/// let data = Colors {
71/// one_rgb: orange,
72/// rgbs_in_vec: vec![green, pink],
73/// };
74/// let json = serde_json::json!({
75/// "one_rgb": [255, 128, 0],
76/// "rgbs_in_vec": [
77/// [0, 255, 0],
78/// [255, 0, 255]
79/// ]
80/// });
81///
82/// assert_eq!(json, serde_json::to_value(&data).unwrap());
83/// assert_eq!(data, serde_json::from_value(json).unwrap());
84///
85/// //////////////////////////////////////////////////
86///
87/// // The types generated by `serde_conv` is also compatible with serde's with attribute
88///
89/// #[derive(Debug, PartialEq, Serialize, Deserialize)]
90/// struct ColorsWith {
91/// #[serde(with = "RgbAsArray")]
92/// rgb_with: Rgb,
93/// }
94///
95/// let data = ColorsWith {
96/// rgb_with: pink,
97/// };
98/// let json = serde_json::json!({
99/// "rgb_with": [255, 0, 255]
100/// });
101///
102/// assert_eq!(json, serde_json::to_value(&data).unwrap());
103/// assert_eq!(data, serde_json::from_value(json).unwrap());
104/// # }
105/// ```
106#[macro_export]
107macro_rules! serde_conv {
108 ($m:ident, $t:ty, $ser:expr, $de:expr) => {$crate::serde_conv!(pub(self) $m, $t, $ser, $de);};
109 ($vis:vis $m:ident, $t:ty, $ser:expr, $de:expr) => {
110 #[allow(non_camel_case_types)]
111 $vis struct $m;
112
113 // Prevent clippy lints triggering because of the template here
114 // https://github.com/jonasbb/serde_with/pull/320
115 // https://github.com/jonasbb/serde_with/pull/729
116 #[allow(clippy::all)]
117 const _:() = {
118 impl $m {
119 $vis fn serialize<S>(x: &$t, serializer: S) -> $crate::__private__::Result<S::Ok, S::Error>
120 where
121 S: $crate::serde::Serializer,
122 {
123 let y = $ser(x);
124 $crate::serde::Serialize::serialize(&y, serializer)
125 }
126
127 $vis fn deserialize<'de, D>(deserializer: D) -> $crate::__private__::Result<$t, D::Error>
128 where
129 D: $crate::serde::Deserializer<'de>,
130 {
131 let y = $crate::serde::Deserialize::deserialize(deserializer)?;
132 $de(y).map_err($crate::serde::de::Error::custom)
133 }
134 }
135
136 impl $crate::SerializeAs<$t> for $m {
137 fn serialize_as<S>(x: &$t, serializer: S) -> $crate::__private__::Result<S::Ok, S::Error>
138 where
139 S: $crate::serde::Serializer,
140 {
141 Self::serialize(x, serializer)
142 }
143 }
144
145 impl<'de> $crate::DeserializeAs<'de, $t> for $m {
146 fn deserialize_as<D>(deserializer: D) -> $crate::__private__::Result<$t, D::Error>
147 where
148 D: $crate::serde::Deserializer<'de>,
149 {
150 Self::deserialize(deserializer)
151 }
152 }
153 };
154 };
155}