quick_xml/serde_helpers.rs
1//! Provides helper functions to glue an XML with a serde content model.
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5#[macro_export]
6#[doc(hidden)]
7macro_rules! deserialize_variant {
8 // Produce struct enum variant
9 ( $de:expr, $enum:tt, $variant:ident {
10 $(
11 $(#[$meta:meta])*
12 $field:ident : $typ:ty
13 ),* $(,)?
14 } ) => ({
15 let var = {
16 // Create anonymous type
17 #[derive(serde::Deserialize)]
18 struct $variant {
19 $(
20 $(#[$meta])*
21 $field: $typ,
22 )*
23 }
24 <$variant>::deserialize($de)?
25 };
26 // Due to https://github.com/rust-lang/rust/issues/86935 we cannot use
27 // <$enum> :: $variant
28 use $enum :: *;
29 $variant {
30 $($field: var.$field,)*
31 }
32 });
33
34 // Produce newtype enum variant
35 ( $de:expr, $enum:tt, $variant:ident($typ:ty) ) => ({
36 let var = <$typ>::deserialize($de)?;
37 <$enum> :: $variant(var)
38 });
39
40 // Produce unit enum variant
41 ( $de:expr, $enum:tt, $variant:ident ) => ({
42 serde::de::IgnoredAny::deserialize($de)?;
43 <$enum> :: $variant
44 });
45}
46
47/// A helper to implement [`Deserialize`] for [internally tagged] enums which
48/// does not use [`Deserializer::deserialize_any`] that produces wrong results
49/// with XML because of [serde#1183].
50///
51/// In contrast to deriving [`Deserialize`] this macro assumes that a tag will be
52/// the first element or attribute in the XML.
53///
54/// # Example
55///
56/// ```
57/// # use pretty_assertions::assert_eq;
58/// use quick_xml::de::from_str;
59/// use quick_xml::impl_deserialize_for_internally_tagged_enum;
60/// use serde::Deserialize;
61///
62/// #[derive(Deserialize, Debug, PartialEq)]
63/// struct Root {
64/// one: InternallyTaggedEnum,
65/// two: InternallyTaggedEnum,
66/// three: InternallyTaggedEnum,
67/// }
68///
69/// #[derive(Debug, PartialEq)]
70/// // #[serde(tag = "@tag")]
71/// enum InternallyTaggedEnum {
72/// Unit,
73/// Newtype(Newtype),
74/// Struct {
75/// // #[serde(rename = "@attribute")]
76/// attribute: u32,
77/// element: f32,
78/// },
79/// }
80///
81/// #[derive(Deserialize, Debug, PartialEq)]
82/// struct Newtype {
83/// #[serde(rename = "@attribute")]
84/// attribute: u64,
85/// }
86///
87/// // The macro needs the type of the enum, the tag name,
88/// // and information about all the variants
89/// impl_deserialize_for_internally_tagged_enum!{
90/// InternallyTaggedEnum, "@tag",
91/// ("Unit" => Unit),
92/// ("Newtype" => Newtype(Newtype)),
93/// ("Struct" => Struct {
94/// #[serde(rename = "@attribute")]
95/// attribute: u32,
96/// element: f32,
97/// }),
98/// }
99///
100/// assert_eq!(
101/// from_str::<Root>(r#"
102/// <root>
103/// <one tag="Unit" />
104/// <two tag="Newtype" attribute="42" />
105/// <three tag="Struct" attribute="42">
106/// <element>4.2</element>
107/// </three>
108/// </root>
109/// "#).unwrap(),
110/// Root {
111/// one: InternallyTaggedEnum::Unit,
112/// two: InternallyTaggedEnum::Newtype(Newtype { attribute: 42 }),
113/// three: InternallyTaggedEnum::Struct {
114/// attribute: 42,
115/// element: 4.2,
116/// },
117/// },
118/// );
119/// ```
120///
121/// [internally tagged]: https://serde.rs/enum-representations.html#internally-tagged
122/// [serde#1183]: https://github.com/serde-rs/serde/issues/1183
123#[macro_export(local_inner_macros)]
124macro_rules! impl_deserialize_for_internally_tagged_enum {
125 (
126 $enum:ty,
127 $tag:literal,
128 $(
129 ($variant_tag:literal => $($variant:tt)+ )
130 ),* $(,)?
131 ) => {
132 impl<'de> serde::de::Deserialize<'de> for $enum {
133 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
134 where
135 D: serde::de::Deserializer<'de>,
136 {
137 use serde::de::{Error, MapAccess, Visitor};
138
139 // The Visitor struct is normally used for state, but none is needed
140 struct TheVisitor;
141 // The main logic of the deserializing happens in the Visitor trait
142 impl<'de> Visitor<'de> for TheVisitor {
143 // The type that is being deserialized
144 type Value = $enum;
145
146 // Try to give a better error message when this is used wrong
147 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
148 f.write_str("expecting map with tag in ")?;
149 f.write_str($tag)
150 }
151
152 // The xml data is provided as an opaque map,
153 // that map is parsed into the type
154 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
155 where
156 A: MapAccess<'de>,
157 {
158 // Here the assumption is made that only one attribute
159 // exists and it's the discriminator (enum "tag").
160 let entry: Option<(String, String)> = map.next_entry()?;
161 // If there are more attributes those would need
162 // to be parsed as well.
163 let tag = match entry {
164 // Return an error if the no attributes are found,
165 // and indicate that the @tag attribute is missing.
166 None => Err(A::Error::missing_field($tag)),
167 // Check if the attribute is the tag
168 Some((attribute, value)) => {
169 if attribute == $tag {
170 // return the value of the tag
171 Ok(value)
172 } else {
173 // The attribute is not @tag, return an error
174 // indicating that there is an unexpected attribute
175 Err(A::Error::unknown_field(&attribute, &[$tag]))
176 }
177 }
178 }?;
179
180 let de = serde::de::value::MapAccessDeserializer::new(map);
181 match tag.as_ref() {
182 $(
183 $variant_tag => Ok(deserialize_variant!( de, $enum, $($variant)+ )),
184 )*
185 _ => Err(A::Error::unknown_field(&tag, &[$($variant_tag),+])),
186 }
187 }
188 }
189 // Tell the deserializer to deserialize the data as a map,
190 // using the TheVisitor as the decoder
191 deserializer.deserialize_map(TheVisitor)
192 }
193 }
194 }
195}
196
197/// Provides helper functions to serialization and deserialization of types
198/// (usually enums) as a text content of an element and intended to use with
199/// [`#[serde(with = "...")]`][with], [`#[serde(deserialize_with = "...")]`][de-with]
200/// and [`#[serde(serialize_with = "...")]`][se-with].
201///
202/// ```
203/// # use pretty_assertions::assert_eq;
204/// use quick_xml::de::from_str;
205/// use quick_xml::se::to_string;
206/// use serde::{Serialize, Deserialize};
207///
208/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
209/// enum SomeEnum {
210/// // Default implementation serializes enum as an `<EnumValue/>` element
211/// EnumValue,
212/// # /*
213/// ...
214/// # */
215/// }
216///
217/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
218/// #[serde(rename = "some-container")]
219/// struct SomeContainer {
220/// #[serde(with = "quick_xml::serde_helpers::text_content")]
221/// field: SomeEnum,
222/// }
223///
224/// let container = SomeContainer {
225/// field: SomeEnum::EnumValue,
226/// };
227/// let xml = "\
228/// <some-container>\
229/// <field>EnumValue</field>\
230/// </some-container>";
231///
232/// assert_eq!(to_string(&container).unwrap(), xml);
233/// assert_eq!(from_str::<SomeContainer>(xml).unwrap(), container);
234/// ```
235///
236/// Using of this module is equivalent to replacing `field`'s type to this:
237///
238/// ```
239/// # use serde::{Deserialize, Serialize};
240/// # type SomeEnum = ();
241/// #[derive(Serialize, Deserialize)]
242/// struct Field {
243/// // Use a special name `$text` to map field to the text content
244/// #[serde(rename = "$text")]
245/// content: SomeEnum,
246/// }
247///
248/// #[derive(Serialize, Deserialize)]
249/// #[serde(rename = "some-container")]
250/// struct SomeContainer {
251/// field: Field,
252/// }
253/// ```
254/// Read about the meaning of a special [`$text`] field.
255///
256/// In versions of quick-xml before 0.31.0 this module used to represent enum
257/// unit variants as `<field>EnumUnitVariant</field>` instead of `<EnumUnitVariant/>`.
258/// Since version 0.31.0 this is default representation of enums in normal fields,
259/// and `<EnumUnitVariant/>` requires `$value` field:
260///
261/// ```
262/// # use pretty_assertions::assert_eq;
263/// use quick_xml::de::from_str;
264/// use quick_xml::se::to_string;
265/// use serde::{Serialize, Deserialize};
266///
267/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
268/// enum SomeEnum {
269/// // Default implementation serializes enum as an `<EnumValue/>` element
270/// EnumValue,
271/// # /*
272/// ...
273/// # */
274/// }
275///
276/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
277/// #[serde(rename = "some-container")]
278/// struct SomeContainer {
279/// #[serde(rename = "$value")]
280/// field: SomeEnum,
281/// }
282///
283/// let container = SomeContainer {
284/// field: SomeEnum::EnumValue,
285/// };
286/// let xml = "\
287/// <some-container>\
288/// <EnumValue/>\
289/// </some-container>";
290///
291/// assert_eq!(to_string(&container).unwrap(), xml);
292/// assert_eq!(from_str::<SomeContainer>(xml).unwrap(), container);
293/// ```
294///
295/// [with]: https://serde.rs/field-attrs.html#with
296/// [de-with]: https://serde.rs/field-attrs.html#deserialize_with
297/// [se-with]: https://serde.rs/field-attrs.html#serialize_with
298/// [`$text`]: ../../de/index.html#text
299pub mod text_content {
300 use super::*;
301
302 /// Serializes `value` as an XSD [simple type]. Intended to use with
303 /// `#[serde(serialize_with = "...")]`. See example at [`text_content`]
304 /// module level.
305 ///
306 /// [simple type]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
307 pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
308 where
309 S: Serializer,
310 T: Serialize,
311 {
312 #[derive(Serialize)]
313 struct Field<'a, T> {
314 #[serde(rename = "$text")]
315 value: &'a T,
316 }
317 Field { value }.serialize(serializer)
318 }
319
320 /// Deserializes XSD's [simple type]. Intended to use with
321 /// `#[serde(deserialize_with = "...")]`. See example at [`text_content`]
322 /// module level.
323 ///
324 /// [simple type]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
325 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
326 where
327 D: Deserializer<'de>,
328 T: Deserialize<'de>,
329 {
330 #[derive(Deserialize)]
331 struct Field<T> {
332 #[serde(rename = "$text")]
333 value: T,
334 }
335 Ok(Field::deserialize(deserializer)?.value)
336 }
337}