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/// // #[serde(tag = "@tag")]
189/// enum InternallyTaggedEnum {
190/// NewType(Newtype),
191/// Other,
192/// }
193///
194/// #[derive(Deserialize, Debug, PartialEq)]
195/// struct Newtype {
196/// #[serde(rename = "@attribute")]
197/// attribute: u64,
198/// }
199///
200/// // The macro needs the type of the enum, the tag name,
201/// // and information about all the variants
202/// impl_deserialize_for_internally_tagged_enum!{
203/// InternallyTaggedEnum, "@tag",
204/// ("NewType" => NewType(Newtype)),
205/// (_ => Other),
206/// }
207///
208/// assert_eq!(
209/// from_str::<Root>(r#"
210/// <root>
211/// <one tag="NewType" attribute="42" />
212/// <two tag="Something" ignoredAttribute="something" />
213/// <three tag="SomethingElse">
214/// <ignoredToo />
215/// </three>
216/// </root>
217/// "#).unwrap(),
218/// Root {
219/// one: InternallyTaggedEnum::NewType(Newtype { attribute: 42 }),
220/// two: InternallyTaggedEnum::Other,
221/// three: InternallyTaggedEnum::Other,
222/// },
223/// );
224/// ```
225///
226/// If some struct or newtype variants have the specially named `$text` or `$value` fields,
227/// you need to say that to the generated `Deserialize` implementation. XML deserializer
228/// uses presence of that fields to determine if it need to emit such keys. You may specify,
229/// which keys should be available in square brackets just after the tag name and colon:
230///
231/// ```
232/// # use pretty_assertions::assert_eq;
233/// use quick_xml::de::from_str;
234/// use quick_xml::impl_deserialize_for_internally_tagged_enum;
235/// use serde::Deserialize;
236///
237/// #[derive(Deserialize, Debug, PartialEq)]
238/// struct Root {
239/// one: InternallyTaggedEnum,
240/// two: InternallyTaggedEnum,
241/// }
242///
243/// #[derive(Deserialize, Debug, PartialEq)]
244/// enum ExternallyTaggedEnum {
245/// First,
246/// Second,
247/// }
248/// #[derive(Debug, PartialEq)]
249/// // #[serde(tag = "@tag")]
250/// enum InternallyTaggedEnum {
251/// NewType(Newtype),
252/// Struct {
253/// // #[serde(rename = "$value")]
254/// any: ExternallyTaggedEnum,
255/// },
256/// }
257///
258/// #[derive(Deserialize, Debug, PartialEq)]
259/// struct Newtype {
260/// #[serde(rename = "$value")]
261/// any: ExternallyTaggedEnum,
262/// }
263///
264/// // The macro needs the type of the enum, the tag name, the list of fields,
265/// // and information about all the variants
266/// impl_deserialize_for_internally_tagged_enum!{
267/// // Without "$value" you get
268/// // called `Result::unwrap()` on an `Err` value: Custom("missing field `$value`")
269/// // That list will be passed to `deserialize_struct`
270/// InternallyTaggedEnum, "@tag": ["$value"],
271///
272/// ("NewType" => NewType(Newtype)),
273/// ("Struct" => Struct {
274/// #[serde(rename = "$value")]
275/// any: ExternallyTaggedEnum,
276/// }),
277/// }
278///
279/// assert_eq!(
280/// from_str::<Root>(r#"
281/// <root>
282/// <one tag="NewType">
283/// <First />
284/// </one>
285/// <two tag="Struct">
286/// <Second />
287/// </two>
288/// </root>
289/// "#).unwrap(),
290/// Root {
291/// one: InternallyTaggedEnum::NewType(Newtype { any: ExternallyTaggedEnum::First }),
292/// two: InternallyTaggedEnum::Struct { any: ExternallyTaggedEnum::Second },
293/// },
294/// );
295/// ```
296/// <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
297///
298/// NOTE: In addition to `$value` you must specify _all_ field names that may appear
299/// in every variant! Otherwise you'll get ```Custom("missing field `unlisted field name`")```
300/// error. That is because XML tags for all unlisted field names would be mapped to field `$value`.
301/// If your types do not have a `$value` special field, you may omit the field list.
302///
303/// </div>
304///
305/// [internally tagged]: https://serde.rs/enum-representations.html#internally-tagged
306/// [serde#1183]: https://github.com/serde-rs/serde/issues/1183
307#[macro_export(local_inner_macros)]
308macro_rules! impl_deserialize_for_internally_tagged_enum {
309 (
310 $enum:ty,
311 $tag:literal $(:[ $($field:literal),* ])?,
312 $($cases:tt)*
313 ) => {
314 impl<'de> serde::de::Deserialize<'de> for $enum {
315 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
316 where
317 D: serde::de::Deserializer<'de>,
318 {
319 use serde::de::{Error, MapAccess, Visitor};
320
321 // The Visitor struct is normally used for state, but none is needed
322 struct TheVisitor;
323 // The main logic of the deserializing happens in the Visitor trait
324 impl<'de> Visitor<'de> for TheVisitor {
325 // The type that is being deserialized
326 type Value = $enum;
327
328 // Try to give a better error message when this is used wrong
329 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
330 f.write_str("expecting map with tag in ")?;
331 f.write_str($tag)
332 }
333
334 // The xml data is provided as an opaque map,
335 // that map is parsed into the type
336 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
337 where
338 A: MapAccess<'de>,
339 {
340 // Here the assumption is made that only one attribute
341 // exists and it's the discriminator (enum "tag").
342 let entry: Option<(String, String)> = map.next_entry()?;
343 // If there are more attributes those would need
344 // to be parsed as well.
345 let tag = match entry {
346 // Return an error if the no attributes are found,
347 // and indicate that the @tag attribute is missing.
348 None => Err(A::Error::missing_field($tag)),
349 // Check if the attribute is the tag
350 Some((attribute, value)) => {
351 if attribute == $tag {
352 // return the value of the tag
353 Ok(value)
354 } else {
355 // The attribute is not @tag, return an error
356 // indicating that there is an unexpected attribute
357 Err(A::Error::unknown_field(&attribute, &[$tag]))
358 }
359 }
360 }?;
361
362 let de = serde::de::value::MapAccessDeserializer::new(map);
363 $crate::deserialize_match!( tag, de, $enum, $($cases)* )
364 }
365 }
366 // Tell the deserializer to deserialize the data as a map,
367 // using the TheVisitor as the decoder
368 deserializer.deserialize_struct(std::stringify!($enum), &[ $($($field),*)? ], TheVisitor)
369 }
370 }
371 }
372}
373
374/// Provides helper functions to serialization and deserialization of types
375/// (usually enums) as a text content of an element and intended to use with
376/// [`#[serde(with = "...")]`][with], [`#[serde(deserialize_with = "...")]`][de-with]
377/// and [`#[serde(serialize_with = "...")]`][se-with].
378///
379/// ```
380/// # use pretty_assertions::assert_eq;
381/// use quick_xml::de::from_str;
382/// use quick_xml::se::to_string;
383/// use serde::{Serialize, Deserialize};
384///
385/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
386/// enum SomeEnum {
387/// // Default implementation serializes enum as an `<EnumValue/>` element
388/// EnumValue,
389/// # /*
390/// ...
391/// # */
392/// }
393///
394/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
395/// #[serde(rename = "some-container")]
396/// struct SomeContainer {
397/// #[serde(with = "quick_xml::serde_helpers::text_content")]
398/// field: SomeEnum,
399/// }
400///
401/// let container = SomeContainer {
402/// field: SomeEnum::EnumValue,
403/// };
404/// let xml = "\
405/// <some-container>\
406/// <field>EnumValue</field>\
407/// </some-container>";
408///
409/// assert_eq!(to_string(&container).unwrap(), xml);
410/// assert_eq!(from_str::<SomeContainer>(xml).unwrap(), container);
411/// ```
412///
413/// Using of this module is equivalent to replacing `field`'s type to this:
414///
415/// ```
416/// # use serde::{Deserialize, Serialize};
417/// # type SomeEnum = ();
418/// #[derive(Serialize, Deserialize)]
419/// struct Field {
420/// // Use a special name `$text` to map field to the text content
421/// #[serde(rename = "$text")]
422/// content: SomeEnum,
423/// }
424///
425/// #[derive(Serialize, Deserialize)]
426/// #[serde(rename = "some-container")]
427/// struct SomeContainer {
428/// field: Field,
429/// }
430/// ```
431/// Read about the meaning of a special [`$text`] field.
432///
433/// In versions of quick-xml before 0.31.0 this module used to represent enum
434/// unit variants as `<field>EnumUnitVariant</field>` instead of `<EnumUnitVariant/>`.
435/// Since version 0.31.0 this is default representation of enums in normal fields,
436/// and `<EnumUnitVariant/>` requires `$value` field:
437///
438/// ```
439/// # use pretty_assertions::assert_eq;
440/// use quick_xml::de::from_str;
441/// use quick_xml::se::to_string;
442/// use serde::{Serialize, Deserialize};
443///
444/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
445/// enum SomeEnum {
446/// // Default implementation serializes enum as an `<EnumValue/>` element
447/// EnumValue,
448/// # /*
449/// ...
450/// # */
451/// }
452///
453/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
454/// #[serde(rename = "some-container")]
455/// struct SomeContainer {
456/// #[serde(rename = "$value")]
457/// field: SomeEnum,
458/// }
459///
460/// let container = SomeContainer {
461/// field: SomeEnum::EnumValue,
462/// };
463/// let xml = "\
464/// <some-container>\
465/// <EnumValue/>\
466/// </some-container>";
467///
468/// assert_eq!(to_string(&container).unwrap(), xml);
469/// assert_eq!(from_str::<SomeContainer>(xml).unwrap(), container);
470/// ```
471///
472/// [with]: https://serde.rs/field-attrs.html#with
473/// [de-with]: https://serde.rs/field-attrs.html#deserialize_with
474/// [se-with]: https://serde.rs/field-attrs.html#serialize_with
475/// [`$text`]: ../../de/index.html#text
476pub mod text_content {
477 use super::*;
478
479 /// Serializes `value` as an XSD [simple type]. Intended to use with
480 /// `#[serde(serialize_with = "...")]`. See example at [`text_content`]
481 /// module level.
482 ///
483 /// [simple type]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
484 pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
485 where
486 S: Serializer,
487 T: Serialize,
488 {
489 #[derive(Serialize)]
490 struct Field<'a, T> {
491 #[serde(rename = "$text")]
492 value: &'a T,
493 }
494 Field { value }.serialize(serializer)
495 }
496
497 /// Deserializes XSD's [simple type]. Intended to use with
498 /// `#[serde(deserialize_with = "...")]`. See example at [`text_content`]
499 /// module level.
500 ///
501 /// [simple type]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
502 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
503 where
504 D: Deserializer<'de>,
505 T: Deserialize<'de>,
506 {
507 #[derive(Deserialize)]
508 struct Field<T> {
509 #[serde(rename = "$text")]
510 value: T,
511 }
512 Ok(Field::deserialize(deserializer)?.value)
513 }
514}