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/// Helper macro that generates different match expressions depending on the presence
48/// of default variant
49#[macro_export]
50#[doc(hidden)]
51macro_rules! deserialize_match {
52    // Only default variant
53    (
54        $tag:ident, $de:ident, $enum:ty,
55        (_ => $($default_variant:tt)+ )
56        $(,)?
57    ) => (
58        Ok($crate::deserialize_variant!( $de, $enum, $($default_variant)+ ))
59    );
60
61    // With default variant
62    (
63        $tag:ident, $de:ident, $enum:ty,
64        $(
65            ($variant_tag:literal => $($variant:tt)+ )
66        ),*
67        , (_ => $($default_variant:tt)+ )
68        $(,)?
69    ) => (
70        match $tag.as_ref() {
71            $(
72                $variant_tag => Ok($crate::deserialize_variant!( $de, $enum, $($variant)+ )),
73            )*
74            _ => Ok($crate::deserialize_variant!( $de, $enum, $($default_variant)+ )),
75        }
76    );
77
78    // Without default variant
79    (
80        $tag:ident, $de:ident, $enum:ty,
81        $(
82            ($variant_tag:literal => $($variant:tt)+ )
83        ),*
84        $(,)?
85    ) => (
86        match $tag.as_ref() {
87            $(
88                $variant_tag => Ok($crate::deserialize_variant!( $de, $enum, $($variant)+ )),
89            )*
90            _ => Err(A::Error::unknown_field(&$tag, &[$($variant_tag),+])),
91        }
92    );
93}
94
95/// A helper to implement [`Deserialize`] for [internally tagged] enums which
96/// does not use [`Deserializer::deserialize_any`] that produces wrong results
97/// with XML because of [serde#1183].
98///
99/// In contrast to deriving [`Deserialize`] this macro assumes that a tag will be
100/// the first element or attribute in the XML.
101///
102/// # Example
103///
104/// ```
105/// # use pretty_assertions::assert_eq;
106/// use quick_xml::de::from_str;
107/// use quick_xml::impl_deserialize_for_internally_tagged_enum;
108/// use serde::Deserialize;
109///
110/// #[derive(Deserialize, Debug, PartialEq)]
111/// struct Root {
112///     one: InternallyTaggedEnum,
113///     two: InternallyTaggedEnum,
114///     three: InternallyTaggedEnum,
115/// }
116///
117/// #[derive(Debug, PartialEq)]
118/// // #[serde(tag = "@tag")]
119/// enum InternallyTaggedEnum {
120///     Unit,
121///     Newtype(Newtype),
122///     Struct {
123///         // #[serde(rename = "@attribute")]
124///         attribute: u32,
125///         element: f32,
126///     },
127/// }
128///
129/// #[derive(Deserialize, Debug, PartialEq)]
130/// struct Newtype {
131///     #[serde(rename = "@attribute")]
132///     attribute: u64,
133/// }
134///
135/// // The macro needs the type of the enum, the tag name,
136/// // and information about all the variants
137/// impl_deserialize_for_internally_tagged_enum!{
138///     InternallyTaggedEnum, "@tag",
139///     ("Unit"    => Unit),
140///     ("Newtype" => Newtype(Newtype)),
141///     ("Struct"  => Struct {
142///         #[serde(rename = "@attribute")]
143///         attribute: u32,
144///         element: f32,
145///     }),
146/// }
147///
148/// assert_eq!(
149///     from_str::<Root>(r#"
150///         <root>
151///             <one tag="Unit" />
152///             <two tag="Newtype" attribute="42" />
153///             <three tag="Struct" attribute="42">
154///                 <element>4.2</element>
155///             </three>
156///         </root>
157///     "#).unwrap(),
158///     Root {
159///         one: InternallyTaggedEnum::Unit,
160///         two: InternallyTaggedEnum::Newtype(Newtype { attribute: 42 }),
161///         three: InternallyTaggedEnum::Struct {
162///             attribute: 42,
163///             element: 4.2,
164///         },
165///     },
166/// );
167/// ```
168///
169/// You don't necessarily have to provide all the enumeration variants and can use
170/// `_` to put every undefined tag into an enumeration variant.
171/// This default variant (`_ => ...`) must be the last one to appear in the macro,
172/// like `_ => Other` in the example below:
173///
174/// ```
175/// # use pretty_assertions::assert_eq;
176/// use quick_xml::de::from_str;
177/// use quick_xml::impl_deserialize_for_internally_tagged_enum;
178/// use serde::Deserialize;
179///
180/// #[derive(Deserialize, Debug, PartialEq)]
181/// struct Root {
182///     one: InternallyTaggedEnum,
183///     two: InternallyTaggedEnum,
184///     three: InternallyTaggedEnum,
185/// }
186///
187/// #[derive(Debug, PartialEq)]
188/// enum InternallyTaggedEnum {
189///     NewType(Newtype),
190///     Other,
191/// }
192///
193/// #[derive(Deserialize, Debug, PartialEq)]
194/// struct Newtype {
195///     #[serde(rename = "@attribute")]
196///     attribute: u64,
197/// }
198///
199/// // The macro needs the type of the enum, the tag name,
200/// // and information about all the variants
201/// impl_deserialize_for_internally_tagged_enum!{
202///     InternallyTaggedEnum, "@tag",
203///     ("NewType" => NewType(Newtype)),
204///     (_ => Other),
205/// }
206///
207/// assert_eq!(
208///     from_str::<Root>(r#"
209///         <root>
210///             <one tag="NewType" attribute="42" />
211///             <two tag="Something" ignoredAttribute="something" />
212///             <three tag="SomethingElse">
213///                 <ignoredToo />
214///             </three>
215///         </root>
216///     "#).unwrap(),
217///     Root {
218///         one: InternallyTaggedEnum::NewType(Newtype { attribute: 42 }),
219///         two: InternallyTaggedEnum::Other,
220///         three: InternallyTaggedEnum::Other,
221///     },
222/// );
223/// ```
224///
225/// [internally tagged]: https://serde.rs/enum-representations.html#internally-tagged
226/// [serde#1183]: https://github.com/serde-rs/serde/issues/1183
227#[macro_export(local_inner_macros)]
228macro_rules! impl_deserialize_for_internally_tagged_enum {
229    (
230        $enum:ty,
231        $tag:literal,
232        $($cases:tt)*
233    ) => {
234        impl<'de> serde::de::Deserialize<'de> for $enum {
235            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
236            where
237                D: serde::de::Deserializer<'de>,
238            {
239                use serde::de::{Error, MapAccess, Visitor};
240
241                // The Visitor struct is normally used for state, but none is needed
242                struct TheVisitor;
243                // The main logic of the deserializing happens in the Visitor trait
244                impl<'de> Visitor<'de> for TheVisitor {
245                    // The type that is being deserialized
246                    type Value = $enum;
247
248                    // Try to give a better error message when this is used wrong
249                    fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
250                        f.write_str("expecting map with tag in ")?;
251                        f.write_str($tag)
252                    }
253
254                    // The xml data is provided as an opaque map,
255                    // that map is parsed into the type
256                    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
257                    where
258                        A: MapAccess<'de>,
259                    {
260                        // Here the assumption is made that only one attribute
261                        // exists and it's the discriminator (enum "tag").
262                        let entry: Option<(String, String)> = map.next_entry()?;
263                        // If there are more attributes those would need
264                        // to be parsed as well.
265                        let tag = match entry {
266                            // Return an error if the no attributes are found,
267                            // and indicate that the @tag attribute is missing.
268                            None => Err(A::Error::missing_field($tag)),
269                            // Check if the attribute is the tag
270                            Some((attribute, value)) => {
271                                if attribute == $tag {
272                                    // return the value of the tag
273                                    Ok(value)
274                                } else {
275                                    // The attribute is not @tag, return an error
276                                    // indicating that there is an unexpected attribute
277                                    Err(A::Error::unknown_field(&attribute, &[$tag]))
278                                }
279                            }
280                        }?;
281
282                        let de = serde::de::value::MapAccessDeserializer::new(map);
283                        $crate::deserialize_match!( tag, de, $enum, $($cases)* )
284                    }
285                }
286                // Tell the deserializer to deserialize the data as a map,
287                // using the TheVisitor as the decoder
288                deserializer.deserialize_map(TheVisitor)
289            }
290        }
291    }
292}
293
294/// Provides helper functions to serialization and deserialization of types
295/// (usually enums) as a text content of an element and intended to use with
296/// [`#[serde(with = "...")]`][with], [`#[serde(deserialize_with = "...")]`][de-with]
297/// and [`#[serde(serialize_with = "...")]`][se-with].
298///
299/// ```
300/// # use pretty_assertions::assert_eq;
301/// use quick_xml::de::from_str;
302/// use quick_xml::se::to_string;
303/// use serde::{Serialize, Deserialize};
304///
305/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
306/// enum SomeEnum {
307///     // Default implementation serializes enum as an `<EnumValue/>` element
308///     EnumValue,
309/// # /*
310///     ...
311/// # */
312/// }
313///
314/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
315/// #[serde(rename = "some-container")]
316/// struct SomeContainer {
317///     #[serde(with = "quick_xml::serde_helpers::text_content")]
318///     field: SomeEnum,
319/// }
320///
321/// let container = SomeContainer {
322///     field: SomeEnum::EnumValue,
323/// };
324/// let xml = "\
325///     <some-container>\
326///         <field>EnumValue</field>\
327///     </some-container>";
328///
329/// assert_eq!(to_string(&container).unwrap(), xml);
330/// assert_eq!(from_str::<SomeContainer>(xml).unwrap(), container);
331/// ```
332///
333/// Using of this module is equivalent to replacing `field`'s type to this:
334///
335/// ```
336/// # use serde::{Deserialize, Serialize};
337/// # type SomeEnum = ();
338/// #[derive(Serialize, Deserialize)]
339/// struct Field {
340///     // Use a special name `$text` to map field to the text content
341///     #[serde(rename = "$text")]
342///     content: SomeEnum,
343/// }
344///
345/// #[derive(Serialize, Deserialize)]
346/// #[serde(rename = "some-container")]
347/// struct SomeContainer {
348///     field: Field,
349/// }
350/// ```
351/// Read about the meaning of a special [`$text`] field.
352///
353/// In versions of quick-xml before 0.31.0 this module used to represent enum
354/// unit variants as `<field>EnumUnitVariant</field>` instead of `<EnumUnitVariant/>`.
355/// Since version 0.31.0 this is default representation of enums in normal fields,
356/// and `<EnumUnitVariant/>` requires `$value` field:
357///
358/// ```
359/// # use pretty_assertions::assert_eq;
360/// use quick_xml::de::from_str;
361/// use quick_xml::se::to_string;
362/// use serde::{Serialize, Deserialize};
363///
364/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
365/// enum SomeEnum {
366///     // Default implementation serializes enum as an `<EnumValue/>` element
367///     EnumValue,
368/// # /*
369///     ...
370/// # */
371/// }
372///
373/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
374/// #[serde(rename = "some-container")]
375/// struct SomeContainer {
376///     #[serde(rename = "$value")]
377///     field: SomeEnum,
378/// }
379///
380/// let container = SomeContainer {
381///     field: SomeEnum::EnumValue,
382/// };
383/// let xml = "\
384///     <some-container>\
385///         <EnumValue/>\
386///     </some-container>";
387///
388/// assert_eq!(to_string(&container).unwrap(), xml);
389/// assert_eq!(from_str::<SomeContainer>(xml).unwrap(), container);
390/// ```
391///
392/// [with]: https://serde.rs/field-attrs.html#with
393/// [de-with]: https://serde.rs/field-attrs.html#deserialize_with
394/// [se-with]: https://serde.rs/field-attrs.html#serialize_with
395/// [`$text`]: ../../de/index.html#text
396pub mod text_content {
397    use super::*;
398
399    /// Serializes `value` as an XSD [simple type]. Intended to use with
400    /// `#[serde(serialize_with = "...")]`. See example at [`text_content`]
401    /// module level.
402    ///
403    /// [simple type]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
404    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
405    where
406        S: Serializer,
407        T: Serialize,
408    {
409        #[derive(Serialize)]
410        struct Field<'a, T> {
411            #[serde(rename = "$text")]
412            value: &'a T,
413        }
414        Field { value }.serialize(serializer)
415    }
416
417    /// Deserializes XSD's [simple type]. Intended to use with
418    /// `#[serde(deserialize_with = "...")]`. See example at [`text_content`]
419    /// module level.
420    ///
421    /// [simple type]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
422    pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
423    where
424        D: Deserializer<'de>,
425        T: Deserialize<'de>,
426    {
427        #[derive(Deserialize)]
428        struct Field<T> {
429            #[serde(rename = "$text")]
430            value: T,
431        }
432        Ok(Field::deserialize(deserializer)?.value)
433    }
434}