quick_xml/se/
element.rs

1//! Contains serializer for an XML element
2
3use crate::de::{TEXT_KEY, VALUE_KEY};
4use crate::errors::serialize::DeError;
5use crate::se::content::ContentSerializer;
6use crate::se::key::QNameSerializer;
7use crate::se::simple_type::{QuoteTarget, SimpleSeq, SimpleTypeSerializer};
8use crate::se::text::TextSerializer;
9use crate::se::{Indent, XmlName};
10use serde::ser::{
11    Impossible, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
12    SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, Serializer,
13};
14use serde::serde_if_integer128;
15use std::fmt::Write;
16
17/// Writes simple type content between [`ElementSerializer::key`] tags.
18macro_rules! write_primitive {
19    ($method:ident ( $ty:ty )) => {
20        fn $method(self, value: $ty) -> Result<Self::Ok, Self::Error> {
21            self.ser.write_wrapped(self.key, |ser| ser.$method(value))
22        }
23    };
24}
25
26////////////////////////////////////////////////////////////////////////////////////////////////////
27
28/// A serializer used to serialize element with specified name. Unlike the [`ContentSerializer`],
29/// this serializer never uses variant names of enum variants, and because of that
30/// it is unable to serialize any enum values, except unit variants.
31///
32/// This serializer is used for an ordinary fields in structs, which are not special
33/// fields named `$text` ([`TEXT_KEY`]) or `$value` ([`VALUE_KEY`]). `$text` field
34/// should be serialized using [`SimpleTypeSerializer`] and `$value` field should be
35/// serialized using [`ContentSerializer`].
36///
37/// This serializer does the following:
38/// - numbers converted to a decimal representation and serialized as `<key>value</key>`;
39/// - booleans serialized ether as `<key>true</key>` or `<key>false</key>`;
40/// - strings and characters are serialized as `<key>value</key>`. In particular,
41///   an empty string is serialized as `<key/>`;
42/// - `None` is serialized as `<key/>`;
43/// - `Some` and newtypes are serialized as an inner type using the same serializer;
44/// - units (`()`) and unit structs are serialized as `<key/>`;
45/// - sequences, tuples and tuple structs are serialized as repeated `<key>` tag.
46///   In particular, empty sequence is serialized to nothing;
47/// - structs are serialized as a sequence of fields wrapped in a `<key>` tag. Each
48///   field is serialized recursively using either `ElementSerializer`, [`ContentSerializer`]
49///   (`$value` fields), or [`SimpleTypeSerializer`] (`$text` fields).
50///   In particular, the empty struct is serialized as `<key/>`;
51/// - maps are serialized as a sequence of entries wrapped in a `<key>` tag. If key is
52///   serialized to a special name, the same rules as for struct fields are applied.
53///   In particular, the empty map is serialized as `<key/>`;
54/// - enums:
55///   - unit variants are serialized as `<key>variant</key>`;
56///   - other variants are not supported ([`DeError::Unsupported`] is returned);
57///
58/// Usage of empty tags depends on the [`ContentSerializer::expand_empty_elements`] setting.
59pub struct ElementSerializer<'w, 'k, W: Write> {
60    /// The inner serializer that contains the settings and mostly do the actual work
61    pub ser: ContentSerializer<'w, 'k, W>,
62    /// Tag name used to wrap serialized types except enum variants which uses the variant name
63    pub(super) key: XmlName<'k>,
64}
65
66impl<'w, 'k, W: Write> Serializer for ElementSerializer<'w, 'k, W> {
67    type Ok = ();
68    type Error = DeError;
69
70    type SerializeSeq = Self;
71    type SerializeTuple = Self;
72    type SerializeTupleStruct = Self;
73    type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
74    type SerializeMap = Map<'w, 'k, W>;
75    type SerializeStruct = Struct<'w, 'k, W>;
76    type SerializeStructVariant = Struct<'w, 'k, W>;
77
78    write_primitive!(serialize_bool(bool));
79
80    write_primitive!(serialize_i8(i8));
81    write_primitive!(serialize_i16(i16));
82    write_primitive!(serialize_i32(i32));
83    write_primitive!(serialize_i64(i64));
84
85    write_primitive!(serialize_u8(u8));
86    write_primitive!(serialize_u16(u16));
87    write_primitive!(serialize_u32(u32));
88    write_primitive!(serialize_u64(u64));
89
90    serde_if_integer128! {
91        write_primitive!(serialize_i128(i128));
92        write_primitive!(serialize_u128(u128));
93    }
94
95    write_primitive!(serialize_f32(f32));
96    write_primitive!(serialize_f64(f64));
97
98    write_primitive!(serialize_char(char));
99    write_primitive!(serialize_bytes(&[u8]));
100
101    fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
102        if value.is_empty() {
103            self.ser.write_empty(self.key)
104        } else {
105            self.ser
106                .write_wrapped(self.key, |ser| ser.serialize_str(value))
107        }
108    }
109
110    /// By serde contract we should serialize key of [`None`] values. If someone
111    /// wants to skip the field entirely, he should use
112    /// `#[serde(skip_serializing_if = "Option::is_none")]`.
113    ///
114    /// In XML when we serialize field, we write field name as:
115    /// - element name, or
116    /// - attribute name
117    ///
118    /// and field value as
119    /// - content of the element, or
120    /// - attribute value
121    ///
122    /// So serialization of `None` works the same as [serialization of `()`](#method.serialize_unit)
123    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
124        self.serialize_unit()
125    }
126
127    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
128        value.serialize(self)
129    }
130
131    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
132        self.ser.write_empty(self.key)
133    }
134
135    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
136        self.ser.write_empty(self.key)
137    }
138
139    /// Writes a tag with name [`Self::key`] and content of unit variant inside.
140    /// If variant is a special `$text` value, then empty tag `<key/>` is written.
141    /// Otherwise a `<key>variant</key>` is written.
142    fn serialize_unit_variant(
143        self,
144        name: &'static str,
145        variant_index: u32,
146        variant: &'static str,
147    ) -> Result<Self::Ok, Self::Error> {
148        if variant == TEXT_KEY {
149            self.ser.write_empty(self.key)
150        } else {
151            self.ser.write_wrapped(self.key, |ser| {
152                ser.serialize_unit_variant(name, variant_index, variant)
153            })
154        }
155    }
156
157    fn serialize_newtype_struct<T: ?Sized + Serialize>(
158        self,
159        _name: &'static str,
160        value: &T,
161    ) -> Result<Self::Ok, Self::Error> {
162        value.serialize(self)
163    }
164
165    /// Always returns [`DeError::Unsupported`]. Newtype variants can be serialized
166    /// only in `$value` fields, which is serialized using [`ContentSerializer`].
167    #[inline]
168    fn serialize_newtype_variant<T: ?Sized + Serialize>(
169        self,
170        name: &'static str,
171        _variant_index: u32,
172        variant: &'static str,
173        _value: &T,
174    ) -> Result<Self::Ok, Self::Error> {
175        Err(DeError::Unsupported(
176            format!(
177                "cannot serialize enum newtype variant `{}::{}`",
178                name, variant
179            )
180            .into(),
181        ))
182    }
183
184    #[inline]
185    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
186        Ok(self)
187    }
188
189    #[inline]
190    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
191        self.serialize_seq(Some(len))
192    }
193
194    #[inline]
195    fn serialize_tuple_struct(
196        self,
197        _name: &'static str,
198        len: usize,
199    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
200        self.serialize_tuple(len)
201    }
202
203    /// Always returns [`DeError::Unsupported`]. Tuple variants can be serialized
204    /// only in `$value` fields, which is serialized using [`ContentSerializer`].
205    #[inline]
206    fn serialize_tuple_variant(
207        self,
208        name: &'static str,
209        _variant_index: u32,
210        variant: &'static str,
211        _len: usize,
212    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
213        Err(DeError::Unsupported(
214            format!(
215                "cannot serialize enum tuple variant `{}::{}`",
216                name, variant
217            )
218            .into(),
219        ))
220    }
221
222    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
223        Ok(Map {
224            ser: self.serialize_struct("", 0)?,
225            key: None,
226        })
227    }
228
229    #[inline]
230    fn serialize_struct(
231        mut self,
232        _name: &'static str,
233        _len: usize,
234    ) -> Result<Self::SerializeStruct, Self::Error> {
235        self.ser.write_indent()?;
236        self.ser.indent.increase();
237
238        self.ser.writer.write_char('<')?;
239        self.ser.writer.write_str(self.key.0)?;
240        Ok(Struct {
241            ser: self,
242            children: String::new(),
243        })
244    }
245
246    /// Always returns [`DeError::Unsupported`]. Struct variants can be serialized
247    /// only in `$value` fields, which is serialized using [`ContentSerializer`].
248    #[inline]
249    fn serialize_struct_variant(
250        self,
251        name: &'static str,
252        _variant_index: u32,
253        variant: &'static str,
254        _len: usize,
255    ) -> Result<Self::SerializeStructVariant, Self::Error> {
256        Err(DeError::Unsupported(
257            format!(
258                "cannot serialize enum struct variant `{}::{}`",
259                name, variant
260            )
261            .into(),
262        ))
263    }
264}
265
266impl<'w, 'k, W: Write> SerializeSeq for ElementSerializer<'w, 'k, W> {
267    type Ok = ();
268    type Error = DeError;
269
270    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
271    where
272        T: ?Sized + Serialize,
273    {
274        value.serialize(ElementSerializer {
275            ser: self.ser.new_seq_element_serializer(),
276            key: self.key,
277        })?;
278        // Write indent for the next element
279        self.ser.write_indent = true;
280        Ok(())
281    }
282
283    #[inline]
284    fn end(self) -> Result<Self::Ok, Self::Error> {
285        Ok(())
286    }
287}
288
289impl<'w, 'k, W: Write> SerializeTuple for ElementSerializer<'w, 'k, W> {
290    type Ok = ();
291    type Error = DeError;
292
293    #[inline]
294    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
295    where
296        T: ?Sized + Serialize,
297    {
298        SerializeSeq::serialize_element(self, value)
299    }
300
301    #[inline]
302    fn end(self) -> Result<Self::Ok, Self::Error> {
303        SerializeSeq::end(self)
304    }
305}
306
307impl<'w, 'k, W: Write> SerializeTupleStruct for ElementSerializer<'w, 'k, W> {
308    type Ok = ();
309    type Error = DeError;
310
311    #[inline]
312    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
313    where
314        T: ?Sized + Serialize,
315    {
316        SerializeSeq::serialize_element(self, value)
317    }
318
319    #[inline]
320    fn end(self) -> Result<Self::Ok, Self::Error> {
321        SerializeSeq::end(self)
322    }
323}
324
325////////////////////////////////////////////////////////////////////////////////////////////////////
326
327/// A serializer for tuple variants. Tuples can be serialized in two modes:
328/// - wrapping each tuple field into a tag
329/// - without wrapping, fields are delimited by a space
330pub enum Tuple<'w, 'k, W: Write> {
331    /// Serialize each tuple field as an element
332    Element(ElementSerializer<'w, 'k, W>),
333    /// Serialize tuple as an `xs:list`: space-delimited content of fields
334    Text(SimpleSeq<'k, &'w mut W>),
335}
336
337impl<'w, 'k, W: Write> SerializeTupleVariant for Tuple<'w, 'k, W> {
338    type Ok = ();
339    type Error = DeError;
340
341    #[inline]
342    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
343    where
344        T: ?Sized + Serialize,
345    {
346        match self {
347            Self::Element(ser) => SerializeTuple::serialize_element(ser, value),
348            Self::Text(ser) => SerializeTuple::serialize_element(ser, value),
349        }
350    }
351
352    #[inline]
353    fn end(self) -> Result<Self::Ok, Self::Error> {
354        match self {
355            Self::Element(ser) => SerializeTuple::end(ser),
356            Self::Text(ser) => SerializeTuple::end(ser).map(|_| ()),
357        }
358    }
359}
360
361////////////////////////////////////////////////////////////////////////////////////////////////////
362
363/// A serializer for struct variants, which serializes the struct contents inside
364/// of wrapping tags (`<${tag}>...</${tag}>`).
365///
366/// Serialization of each field depends on it representation:
367/// - attributes written directly to the higher serializer
368/// - elements buffered into internal buffer and at the end written into higher
369///   serializer
370pub struct Struct<'w, 'k, W: Write> {
371    ser: ElementSerializer<'w, 'k, W>,
372    /// Buffer to store serialized elements
373    // TODO: Customization point: allow direct writing of elements, but all
374    // attributes should be listed first. Fail, if attribute encountered after
375    // element. Use feature to configure
376    children: String,
377}
378
379impl<'w, 'k, W: Write> Struct<'w, 'k, W> {
380    #[inline]
381    fn write_field<T>(&mut self, key: &str, value: &T) -> Result<(), DeError>
382    where
383        T: ?Sized + Serialize,
384    {
385        //TODO: Customization point: allow user to determine if field is attribute or not
386        if let Some(key) = key.strip_prefix('@') {
387            let key = XmlName::try_from(key)?;
388            self.write_attribute(key, value)
389        } else {
390            self.write_element(key, value)
391        }
392    }
393
394    /// Writes `value` as an attribute
395    #[inline]
396    fn write_attribute<T>(&mut self, key: XmlName, value: &T) -> Result<(), DeError>
397    where
398        T: ?Sized + Serialize,
399    {
400        //TODO: Customization point: each attribute on new line
401        self.ser.ser.writer.write_char(' ')?;
402        self.ser.ser.writer.write_str(key.0)?;
403        self.ser.ser.writer.write_char('=')?;
404
405        //TODO: Customization point: preferred quote style
406        self.ser.ser.writer.write_char('"')?;
407        value.serialize(SimpleTypeSerializer {
408            writer: &mut self.ser.ser.writer,
409            target: QuoteTarget::DoubleQAttr,
410            level: self.ser.ser.level,
411            indent: Indent::None,
412        })?;
413        self.ser.ser.writer.write_char('"')?;
414
415        Ok(())
416    }
417
418    /// Writes `value` either as a text content, or as an element.
419    ///
420    /// If `key` has a magic value [`TEXT_KEY`], then `value` serialized as a
421    /// [simple type].
422    ///
423    /// If `key` has a magic value [`VALUE_KEY`], then `value` serialized as a
424    /// [content] without wrapping in tags, otherwise it is wrapped in
425    /// `<${key}>...</${key}>`.
426    ///
427    /// [simple type]: SimpleTypeSerializer
428    /// [content]: ContentSerializer
429    fn write_element<T>(&mut self, key: &str, value: &T) -> Result<(), DeError>
430    where
431        T: ?Sized + Serialize,
432    {
433        let ser = ContentSerializer {
434            writer: &mut self.children,
435            level: self.ser.ser.level,
436            indent: self.ser.ser.indent.borrow(),
437            write_indent: true,
438            expand_empty_elements: self.ser.ser.expand_empty_elements,
439        };
440
441        if key == TEXT_KEY {
442            value.serialize(TextSerializer(ser.into_simple_type_serializer()))?;
443        } else if key == VALUE_KEY {
444            value.serialize(ser)?;
445        } else {
446            value.serialize(ElementSerializer {
447                key: XmlName::try_from(key)?,
448                ser,
449            })?;
450        }
451        Ok(())
452    }
453}
454
455impl<'w, 'k, W: Write> SerializeStruct for Struct<'w, 'k, W> {
456    type Ok = ();
457    type Error = DeError;
458
459    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
460    where
461        T: ?Sized + Serialize,
462    {
463        self.write_field(key, value)
464    }
465
466    fn end(mut self) -> Result<Self::Ok, Self::Error> {
467        self.ser.ser.indent.decrease();
468
469        if self.children.is_empty() {
470            self.ser.ser.writer.write_str("/>")?;
471        } else {
472            self.ser.ser.writer.write_char('>')?;
473            self.ser.ser.writer.write_str(&self.children)?;
474
475            self.ser.ser.indent.write_indent(&mut self.ser.ser.writer)?;
476
477            self.ser.ser.writer.write_str("</")?;
478            self.ser.ser.writer.write_str(self.ser.key.0)?;
479            self.ser.ser.writer.write_char('>')?;
480        }
481        Ok(())
482    }
483}
484
485impl<'w, 'k, W: Write> SerializeStructVariant for Struct<'w, 'k, W> {
486    type Ok = ();
487    type Error = DeError;
488
489    #[inline]
490    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
491    where
492        T: ?Sized + Serialize,
493    {
494        SerializeStruct::serialize_field(self, key, value)
495    }
496
497    #[inline]
498    fn end(self) -> Result<Self::Ok, Self::Error> {
499        SerializeStruct::end(self)
500    }
501}
502
503////////////////////////////////////////////////////////////////////////////////////////////////////
504
505pub struct Map<'w, 'k, W: Write> {
506    ser: Struct<'w, 'k, W>,
507    /// Key, serialized by `QNameSerializer` if consumer uses `serialize_key` +
508    /// `serialize_value` calls instead of `serialize_entry`
509    key: Option<String>,
510}
511
512impl<'w, 'k, W: Write> Map<'w, 'k, W> {
513    fn make_key<T>(&mut self, key: &T) -> Result<String, DeError>
514    where
515        T: ?Sized + Serialize,
516    {
517        key.serialize(QNameSerializer {
518            writer: String::new(),
519        })
520    }
521}
522
523impl<'w, 'k, W: Write> SerializeMap for Map<'w, 'k, W> {
524    type Ok = ();
525    type Error = DeError;
526
527    fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
528    where
529        T: ?Sized + Serialize,
530    {
531        if let Some(_) = self.key.take() {
532            return Err(DeError::Custom(
533                "calling `serialize_key` twice without `serialize_value`".to_string(),
534            ));
535        }
536        self.key = Some(self.make_key(key)?);
537        Ok(())
538    }
539
540    fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
541    where
542        T: ?Sized + Serialize,
543    {
544        if let Some(key) = self.key.take() {
545            return self.ser.write_field(&key, value);
546        }
547        Err(DeError::Custom(
548            "calling `serialize_value` without call of `serialize_key`".to_string(),
549        ))
550    }
551
552    fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
553    where
554        K: ?Sized + Serialize,
555        V: ?Sized + Serialize,
556    {
557        let key = self.make_key(key)?;
558        self.ser.write_field(&key, value)
559    }
560
561    fn end(mut self) -> Result<Self::Ok, Self::Error> {
562        if let Some(key) = self.key.take() {
563            return Err(DeError::Custom(format!(
564                "calling `end` without call of `serialize_value` for key `{key}`"
565            )));
566        }
567        SerializeStruct::end(self.ser)
568    }
569}
570
571////////////////////////////////////////////////////////////////////////////////////////////////////
572
573#[cfg(test)]
574mod tests {
575    use super::*;
576    use crate::se::content::tests::*;
577    use crate::se::{Indent, QuoteLevel};
578    use crate::utils::Bytes;
579    use serde::Serialize;
580    use std::collections::BTreeMap;
581
582    #[derive(Debug, Serialize, PartialEq)]
583    struct OptionalElements {
584        a: Option<&'static str>,
585
586        #[serde(skip_serializing_if = "Option::is_none")]
587        b: Option<&'static str>,
588    }
589    #[derive(Debug, Serialize, PartialEq)]
590    struct OptionalAttributes {
591        #[serde(rename = "@a")]
592        a: Option<&'static str>,
593
594        #[serde(rename = "@b")]
595        #[serde(skip_serializing_if = "Option::is_none")]
596        b: Option<&'static str>,
597    }
598
599    mod without_indent {
600        use super::*;
601        use crate::se::content::tests::Struct;
602        use pretty_assertions::assert_eq;
603
604        /// Checks that given `$data` successfully serialized as `$expected`
605        macro_rules! serialize_as {
606            ($name:ident: $data:expr => $expected:expr) => {
607                #[test]
608                fn $name() {
609                    let mut buffer = String::new();
610                    let ser = ElementSerializer {
611                        ser: ContentSerializer {
612                            writer: &mut buffer,
613                            level: QuoteLevel::Full,
614                            indent: Indent::None,
615                            write_indent: false,
616                            expand_empty_elements: false,
617                        },
618                        key: XmlName("root"),
619                    };
620
621                    $data.serialize(ser).unwrap();
622                    assert_eq!(buffer, $expected);
623                }
624            };
625        }
626
627        /// Checks that attempt to serialize given `$data` results to a
628        /// serialization error `$kind` with `$reason`
629        macro_rules! err {
630            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
631                #[test]
632                fn $name() {
633                    let mut buffer = String::new();
634                    let ser = ElementSerializer {
635                        ser: ContentSerializer {
636                            writer: &mut buffer,
637                            level: QuoteLevel::Full,
638                            indent: Indent::None,
639                            write_indent: false,
640                            expand_empty_elements: false,
641                        },
642                        key: XmlName("root"),
643                    };
644
645                    match $data.serialize(ser).unwrap_err() {
646                        DeError::$kind(e) => assert_eq!(e, $reason),
647                        e => panic!(
648                            "Expected `{}({})`, found `{:?}`",
649                            stringify!($kind),
650                            $reason,
651                            e
652                        ),
653                    }
654                    // We can write something before fail
655                    // assert_eq!(buffer, "");
656                }
657            };
658        }
659
660        serialize_as!(false_: false => "<root>false</root>");
661        serialize_as!(true_:  true  => "<root>true</root>");
662
663        serialize_as!(i8_:    -42i8                => "<root>-42</root>");
664        serialize_as!(i16_:   -4200i16             => "<root>-4200</root>");
665        serialize_as!(i32_:   -42000000i32         => "<root>-42000000</root>");
666        serialize_as!(i64_:   -42000000000000i64   => "<root>-42000000000000</root>");
667        serialize_as!(isize_: -42000000000000isize => "<root>-42000000000000</root>");
668
669        serialize_as!(u8_:    42u8                => "<root>42</root>");
670        serialize_as!(u16_:   4200u16             => "<root>4200</root>");
671        serialize_as!(u32_:   42000000u32         => "<root>42000000</root>");
672        serialize_as!(u64_:   42000000000000u64   => "<root>42000000000000</root>");
673        serialize_as!(usize_: 42000000000000usize => "<root>42000000000000</root>");
674
675        serde_if_integer128! {
676            serialize_as!(i128_: -420000000000000000000000000000i128 => "<root>-420000000000000000000000000000</root>");
677            serialize_as!(u128_:  420000000000000000000000000000u128 => "<root>420000000000000000000000000000</root>");
678        }
679
680        serialize_as!(f32_: 4.2f32 => "<root>4.2</root>");
681        serialize_as!(f64_: 4.2f64 => "<root>4.2</root>");
682
683        serialize_as!(char_non_escaped: 'h' => "<root>h</root>");
684        serialize_as!(char_lt:   '<' => "<root>&lt;</root>");
685        serialize_as!(char_gt:   '>' => "<root>&gt;</root>");
686        serialize_as!(char_amp:  '&' => "<root>&amp;</root>");
687        serialize_as!(char_apos: '\'' => "<root>&apos;</root>");
688        serialize_as!(char_quot: '"' => "<root>&quot;</root>");
689
690        serialize_as!(str_non_escaped: "non-escaped string" => "<root>non-escaped string</root>");
691        serialize_as!(str_escaped: "<\"escaped & string'>" => "<root>&lt;&quot;escaped &amp; string&apos;&gt;</root>");
692
693        err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("`serialize_bytes` not supported yet"));
694
695        serialize_as!(option_none: Option::<&str>::None => "<root/>");
696        serialize_as!(option_some: Some("non-escaped string") => "<root>non-escaped string</root>");
697        serialize_as!(option_some_empty_str: Some("") => "<root/>");
698
699        serialize_as!(unit: () => "<root/>");
700        serialize_as!(unit_struct: Unit => "<root/>");
701        serialize_as!(unit_struct_escaped: UnitEscaped => "<root/>");
702
703        serialize_as!(enum_unit: Enum::Unit => "<root>Unit</root>");
704        serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<root>&lt;&quot;&amp;&apos;&gt;</root>");
705
706        serialize_as!(newtype: Newtype(42) => "<root>42</root>");
707        err!(enum_newtype: Enum::Newtype(42)
708            => Unsupported("cannot serialize enum newtype variant `Enum::Newtype`"));
709
710        serialize_as!(seq: vec![1, 2, 3]
711            => "<root>1</root>\
712                <root>2</root>\
713                <root>3</root>");
714        serialize_as!(seq_empty: Vec::<usize>::new() => "");
715        serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
716            => "<root>&lt;&quot;&amp;&apos;&gt;</root>\
717                <root>with\t\n\r spaces</root>\
718                <root>3</root>");
719        serialize_as!(tuple_struct: Tuple("first", 42)
720            => "<root>first</root>\
721                <root>42</root>");
722        err!(enum_tuple: Enum::Tuple("first", 42)
723            => Unsupported("cannot serialize enum tuple variant `Enum::Tuple`"));
724
725        serialize_as!(map: BTreeMap::from([("_1", 2), ("_3", 4)])
726            => "<root>\
727                    <_1>2</_1>\
728                    <_3>4</_3>\
729                </root>");
730        serialize_as!(struct_: Struct { key: "answer", val: (42, 42) }
731            => "<root>\
732                    <key>answer</key>\
733                    <val>42</val>\
734                    <val>42</val>\
735                </root>");
736        err!(enum_struct: Enum::Struct { key: "answer", val: (42, 42) }
737            => Unsupported("cannot serialize enum struct variant `Enum::Struct`"));
738
739        /// Special field name `$text` should be serialized as text content.
740        /// Sequences serialized as an `xs:list` content
741        mod text_field {
742            use super::*;
743
744            /// `$text` key in a map
745            mod map {
746                use super::*;
747                use pretty_assertions::assert_eq;
748
749                macro_rules! text {
750                    ($name:ident: $data:expr) => {
751                        serialize_as!($name:
752                            BTreeMap::from([("$text", $data)])
753                            => "<root/>");
754                    };
755                    ($name:ident: $data:expr => $expected:literal) => {
756                        serialize_as!($name:
757                            BTreeMap::from([("$text", $data)])
758                            => concat!("<root>", $expected,"</root>"));
759                    };
760                }
761
762                text!(false_: false => "false");
763                text!(true_:  true  => "true");
764
765                text!(i8_:    -42i8                => "-42");
766                text!(i16_:   -4200i16             => "-4200");
767                text!(i32_:   -42000000i32         => "-42000000");
768                text!(i64_:   -42000000000000i64   => "-42000000000000");
769                text!(isize_: -42000000000000isize => "-42000000000000");
770
771                text!(u8_:    42u8                => "42");
772                text!(u16_:   4200u16             => "4200");
773                text!(u32_:   42000000u32         => "42000000");
774                text!(u64_:   42000000000000u64   => "42000000000000");
775                text!(usize_: 42000000000000usize => "42000000000000");
776
777                serde_if_integer128! {
778                    text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
779                    text!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
780                }
781
782                text!(f32_: 4.2f32 => "4.2");
783                text!(f64_: 4.2f64 => "4.2");
784
785                text!(char_non_escaped: 'h' => "h");
786                text!(char_lt:   '<' => "&lt;");
787                text!(char_gt:   '>' => "&gt;");
788                text!(char_amp:  '&' => "&amp;");
789                text!(char_apos: '\'' => "&apos;");
790                text!(char_quot: '"' => "&quot;");
791                //TODO: add a setting to escape leading/trailing spaces, in order to
792                // pretty-print does not change the content
793                text!(char_space: ' ' => " ");
794
795                text!(str_non_escaped: "non-escaped string" => "non-escaped string");
796                text!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
797
798                err!(bytes:
799                    Text {
800                        before: "answer",
801                        content: Bytes(b"<\"escaped & bytes'>"),
802                        after: "answer",
803                    }
804                    => Unsupported("`serialize_bytes` not supported yet"));
805
806                text!(option_none: Option::<&str>::None);
807                text!(option_some: Some("non-escaped string") => "non-escaped string");
808                text!(option_some_empty_str: Some(""));
809
810                text!(unit: ());
811                text!(unit_struct: Unit);
812                text!(unit_struct_escaped: UnitEscaped);
813
814                text!(enum_unit: Enum::Unit => "Unit");
815                text!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
816
817                text!(newtype: Newtype(42) => "42");
818                // We have no space where name of a variant can be stored
819                err!(enum_newtype:
820                    Text {
821                        before: "answer",
822                        content: Enum::Newtype(42),
823                        after: "answer",
824                    }
825                    => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value"));
826
827                // Sequences are serialized separated by spaces, all spaces inside are escaped
828                text!(seq: vec![1, 2, 3] => "1 2 3");
829                text!(seq_empty: Vec::<usize>::new());
830                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
831                    => "&lt;&quot;&amp;&apos;&gt; \
832                        with&#9;&#10;&#13;&#32;spaces \
833                        3");
834                text!(tuple_struct: Tuple("first", 42) => "first 42");
835                // We have no space where name of a variant can be stored
836                err!(enum_tuple:
837                    Text {
838                        before: "answer",
839                        content: Enum::Tuple("first", 42),
840                        after: "answer",
841                    }
842                    => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value"));
843
844                // Complex types cannot be serialized in `$text` field
845                err!(map:
846                    Text {
847                        before: "answer",
848                        content: BTreeMap::from([("_1", 2), ("_3", 4)]),
849                        after: "answer",
850                    }
851                    => Unsupported("cannot serialize map as text content value"));
852                err!(struct_:
853                    Text {
854                        before: "answer",
855                        content: Struct { key: "answer", val: (42, 42) },
856                        after: "answer",
857                    }
858                    => Unsupported("cannot serialize struct `Struct` as text content value"));
859                err!(enum_struct:
860                    Text {
861                        before: "answer",
862                        content: Enum::Struct { key: "answer", val: (42, 42) },
863                        after: "answer",
864                    }
865                    => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value"));
866            }
867
868            /// `$text` field inside a struct
869            mod struct_ {
870                use super::*;
871                use pretty_assertions::assert_eq;
872
873                macro_rules! text {
874                    ($name:ident: $data:expr => $expected:literal) => {
875                        serialize_as!($name:
876                            Text {
877                                before: "answer",
878                                content: $data,
879                                after: "answer",
880                            }
881                            => concat!(
882                                "<root><before>answer</before>",
883                                $expected,
884                                "<after>answer</after></root>",
885                            ));
886                    };
887                }
888
889                text!(false_: false => "false");
890                text!(true_:  true  => "true");
891
892                text!(i8_:    -42i8                => "-42");
893                text!(i16_:   -4200i16             => "-4200");
894                text!(i32_:   -42000000i32         => "-42000000");
895                text!(i64_:   -42000000000000i64   => "-42000000000000");
896                text!(isize_: -42000000000000isize => "-42000000000000");
897
898                text!(u8_:    42u8                => "42");
899                text!(u16_:   4200u16             => "4200");
900                text!(u32_:   42000000u32         => "42000000");
901                text!(u64_:   42000000000000u64   => "42000000000000");
902                text!(usize_: 42000000000000usize => "42000000000000");
903
904                serde_if_integer128! {
905                    text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
906                    text!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
907                }
908
909                text!(f32_: 4.2f32 => "4.2");
910                text!(f64_: 4.2f64 => "4.2");
911
912                text!(char_non_escaped: 'h' => "h");
913                text!(char_lt:   '<' => "&lt;");
914                text!(char_gt:   '>' => "&gt;");
915                text!(char_amp:  '&' => "&amp;");
916                text!(char_apos: '\'' => "&apos;");
917                text!(char_quot: '"' => "&quot;");
918                //TODO: add a setting to escape leading/trailing spaces, in order to
919                // pretty-print does not change the content
920                text!(char_space: ' ' => " ");
921
922                text!(str_non_escaped: "non-escaped string" => "non-escaped string");
923                text!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
924
925                err!(bytes:
926                    Text {
927                        before: "answer",
928                        content: Bytes(b"<\"escaped & bytes'>"),
929                        after: "answer",
930                    }
931                    => Unsupported("`serialize_bytes` not supported yet"));
932
933                text!(option_none: Option::<&str>::None => "");
934                text!(option_some: Some("non-escaped string") => "non-escaped string");
935                text!(option_some_empty_str: Some("") => "");
936
937                text!(unit: () => "");
938                text!(unit_struct: Unit => "");
939                text!(unit_struct_escaped: UnitEscaped => "");
940
941                text!(enum_unit: Enum::Unit => "Unit");
942                text!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
943
944                text!(newtype: Newtype(42) => "42");
945                // We have no space where name of a variant can be stored
946                err!(enum_newtype:
947                    Text {
948                        before: "answer",
949                        content: Enum::Newtype(42),
950                        after: "answer",
951                    }
952                    => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value"));
953
954                // Sequences are serialized separated by spaces, all spaces inside are escaped
955                text!(seq: vec![1, 2, 3] => "1 2 3");
956                text!(seq_empty: Vec::<usize>::new() => "");
957                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
958                    => "&lt;&quot;&amp;&apos;&gt; \
959                        with&#9;&#10;&#13;&#32;spaces \
960                        3");
961                text!(tuple_struct: Tuple("first", 42) => "first 42");
962                // We have no space where name of a variant can be stored
963                err!(enum_tuple:
964                    Text {
965                        before: "answer",
966                        content: Enum::Tuple("first", 42),
967                        after: "answer",
968                    }
969                    => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value"));
970
971                // Complex types cannot be serialized in `$text` field
972                err!(map:
973                    Text {
974                        before: "answer",
975                        content: BTreeMap::from([("_1", 2), ("_3", 4)]),
976                        after: "answer",
977                    }
978                    => Unsupported("cannot serialize map as text content value"));
979                err!(struct_:
980                    Text {
981                        before: "answer",
982                        content: Struct { key: "answer", val: (42, 42) },
983                        after: "answer",
984                    }
985                    => Unsupported("cannot serialize struct `Struct` as text content value"));
986                err!(enum_struct:
987                    Text {
988                        before: "answer",
989                        content: Enum::Struct { key: "answer", val: (42, 42) },
990                        after: "answer",
991                    }
992                    => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value"));
993            }
994        }
995
996        /// Special field name `$value` should be serialized using name, provided
997        /// by the type of value instead of a key. Sequences serialized as a list
998        /// of tags with that name (each element can have their own name)
999        mod value_field {
1000            use super::*;
1001
1002            /// `$value` key in a map
1003            mod map {
1004                use super::*;
1005                use pretty_assertions::assert_eq;
1006
1007                macro_rules! value {
1008                    ($name:ident: $data:expr) => {
1009                        serialize_as!($name:
1010                            BTreeMap::from([("$value", $data)])
1011                            => "<root/>");
1012                    };
1013                    ($name:ident: $data:expr => $expected:literal) => {
1014                        serialize_as!($name:
1015                            BTreeMap::from([("$value", $data)])
1016                            => concat!("<root>", $expected,"</root>"));
1017                    };
1018                }
1019
1020                value!(false_: false => "false");
1021                value!(true_:  true  => "true");
1022
1023                value!(i8_:    -42i8                => "-42");
1024                value!(i16_:   -4200i16             => "-4200");
1025                value!(i32_:   -42000000i32         => "-42000000");
1026                value!(i64_:   -42000000000000i64   => "-42000000000000");
1027                value!(isize_: -42000000000000isize => "-42000000000000");
1028
1029                value!(u8_:    42u8                => "42");
1030                value!(u16_:   4200u16             => "4200");
1031                value!(u32_:   42000000u32         => "42000000");
1032                value!(u64_:   42000000000000u64   => "42000000000000");
1033                value!(usize_: 42000000000000usize => "42000000000000");
1034
1035                serde_if_integer128! {
1036                    value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1037                    value!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1038                }
1039
1040                value!(f32_: 4.2f32 => "4.2");
1041                value!(f64_: 4.2f64 => "4.2");
1042
1043                value!(char_non_escaped: 'h' => "h");
1044                value!(char_lt:   '<' => "&lt;");
1045                value!(char_gt:   '>' => "&gt;");
1046                value!(char_amp:  '&' => "&amp;");
1047                value!(char_apos: '\'' => "&apos;");
1048                value!(char_quot: '"' => "&quot;");
1049                //TODO: add a setting to escape leading/trailing spaces, in order to
1050                // pretty-print does not change the content
1051                value!(char_space: ' ' => " ");
1052
1053                value!(str_non_escaped: "non-escaped string" => "non-escaped string");
1054                value!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1055
1056                err!(bytes:
1057                    BTreeMap::from([("$value", Bytes(b"<\"escaped & bytes'>"))])
1058                    => Unsupported("`serialize_bytes` not supported yet"));
1059
1060                value!(option_none: Option::<&str>::None);
1061                value!(option_some: Some("non-escaped string") => "non-escaped string");
1062                value!(option_some_empty_str: Some(""));
1063
1064                value!(unit: ());
1065                value!(unit_struct: Unit);
1066                value!(unit_struct_escaped: UnitEscaped);
1067
1068                value!(enum_unit: Enum::Unit => "<Unit/>");
1069                err!(enum_unit_escaped:
1070                    BTreeMap::from([("$value", Enum::UnitEscaped)])
1071                    => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
1072
1073                value!(newtype: Newtype(42) => "42");
1074                value!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>");
1075
1076                // Note that sequences of primitives serialized without delimiters!
1077                value!(seq: vec![1, 2, 3] => "123");
1078                value!(seq_empty: Vec::<usize>::new());
1079                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1080                    => "&lt;&quot;&amp;&apos;&gt;\
1081                        with\t\n\r spaces\
1082                        3");
1083                value!(tuple_struct: Tuple("first", 42) => "first42");
1084                value!(enum_tuple: Enum::Tuple("first", 42)
1085                    => "<Tuple>first</Tuple>\
1086                        <Tuple>42</Tuple>");
1087
1088                // We cannot wrap map or struct in any container and should not
1089                // flatten it, so it is impossible to serialize maps and structs
1090                err!(map:
1091                    BTreeMap::from([("$value", BTreeMap::from([("_1", 2), ("_3", 4)]))])
1092                    => Unsupported("serialization of map types is not supported in `$value` field"));
1093                err!(struct_:
1094                    BTreeMap::from([("$value", Struct { key: "answer", val: (42, 42) })])
1095                    => Unsupported("serialization of struct `Struct` is not supported in `$value` field"));
1096                value!(enum_struct:
1097                    Enum::Struct { key: "answer", val: (42, 42) }
1098                    => "<Struct>\
1099                            <key>answer</key>\
1100                            <val>42</val>\
1101                            <val>42</val>\
1102                        </Struct>");
1103            }
1104
1105            /// `$value` field inside a struct
1106            mod struct_ {
1107                use super::*;
1108                use pretty_assertions::assert_eq;
1109
1110                macro_rules! value {
1111                    ($name:ident: $data:expr => $expected:literal) => {
1112                        serialize_as!($name:
1113                            Value {
1114                                before: "answer",
1115                                content: $data,
1116                                after: "answer",
1117                            }
1118                            => concat!(
1119                                "<root><before>answer</before>",
1120                                $expected,
1121                                "<after>answer</after></root>",
1122                            ));
1123                    };
1124                }
1125
1126                value!(false_: false => "false");
1127                value!(true_:  true  => "true");
1128
1129                value!(i8_:    -42i8                => "-42");
1130                value!(i16_:   -4200i16             => "-4200");
1131                value!(i32_:   -42000000i32         => "-42000000");
1132                value!(i64_:   -42000000000000i64   => "-42000000000000");
1133                value!(isize_: -42000000000000isize => "-42000000000000");
1134
1135                value!(u8_:    42u8                => "42");
1136                value!(u16_:   4200u16             => "4200");
1137                value!(u32_:   42000000u32         => "42000000");
1138                value!(u64_:   42000000000000u64   => "42000000000000");
1139                value!(usize_: 42000000000000usize => "42000000000000");
1140
1141                serde_if_integer128! {
1142                    value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1143                    value!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1144                }
1145
1146                value!(f32_: 4.2f32 => "4.2");
1147                value!(f64_: 4.2f64 => "4.2");
1148
1149                value!(char_non_escaped: 'h' => "h");
1150                value!(char_lt:   '<' => "&lt;");
1151                value!(char_gt:   '>' => "&gt;");
1152                value!(char_amp:  '&' => "&amp;");
1153                value!(char_apos: '\'' => "&apos;");
1154                value!(char_quot: '"' => "&quot;");
1155                //TODO: add a setting to escape leading/trailing spaces, in order to
1156                // pretty-print does not change the content
1157                value!(char_space: ' ' => " ");
1158
1159                value!(str_non_escaped: "non-escaped string" => "non-escaped string");
1160                value!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1161
1162                err!(bytes:
1163                    Value {
1164                        before: "answer",
1165                        content: Bytes(b"<\"escaped & bytes'>"),
1166                        after: "answer",
1167                    }
1168                    => Unsupported("`serialize_bytes` not supported yet"));
1169
1170                value!(option_none: Option::<&str>::None => "");
1171                value!(option_some: Some("non-escaped string") => "non-escaped string");
1172                value!(option_some_empty_str: Some("") => "");
1173
1174                value!(unit: () => "");
1175                value!(unit_struct: Unit => "");
1176                value!(unit_struct_escaped: UnitEscaped => "");
1177
1178                value!(enum_unit: Enum::Unit => "<Unit/>");
1179                err!(enum_unit_escaped:
1180                    Value {
1181                        before: "answer",
1182                        content: Enum::UnitEscaped,
1183                        after: "answer",
1184                    }
1185                    => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
1186
1187                value!(newtype: Newtype(42) => "42");
1188                value!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>");
1189
1190                // Note that sequences of primitives serialized without delimiters!
1191                value!(seq: vec![1, 2, 3] => "123");
1192                value!(seq_empty: Vec::<usize>::new() => "");
1193                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1194                    => "&lt;&quot;&amp;&apos;&gt;\
1195                        with\t\n\r spaces\
1196                        3");
1197                value!(tuple_struct: Tuple("first", 42) => "first42");
1198                value!(enum_tuple: Enum::Tuple("first", 42)
1199                    => "<Tuple>first</Tuple>\
1200                        <Tuple>42</Tuple>");
1201
1202                // We cannot wrap map or struct in any container and should not
1203                // flatten it, so it is impossible to serialize maps and structs
1204                err!(map:
1205                    Value {
1206                        before: "answer",
1207                        content: BTreeMap::from([("_1", 2), ("_3", 4)]),
1208                        after: "answer",
1209                    }
1210                    => Unsupported("serialization of map types is not supported in `$value` field"));
1211                err!(struct_:
1212                    Value {
1213                        before: "answer",
1214                        content: Struct { key: "answer", val: (42, 42) },
1215                        after: "answer",
1216                    }
1217                    => Unsupported("serialization of struct `Struct` is not supported in `$value` field"));
1218                value!(enum_struct:
1219                    Enum::Struct { key: "answer", val: (42, 42) }
1220                    => "<Struct>\
1221                            <key>answer</key>\
1222                            <val>42</val>\
1223                            <val>42</val>\
1224                        </Struct>");
1225            }
1226        }
1227
1228        mod attributes {
1229            use super::*;
1230            use pretty_assertions::assert_eq;
1231
1232            serialize_as!(map_attr: BTreeMap::from([("@key1", 1), ("@key2", 2)])
1233                => r#"<root key1="1" key2="2"/>"#);
1234            serialize_as!(map_mixed: BTreeMap::from([("@key1", 1), ("key2", 2)])
1235                => r#"<root key1="1"><key2>2</key2></root>"#);
1236
1237            serialize_as!(struct_: Attributes { key: "answer", val: (42, 42) }
1238                => r#"<root key="answer" val="42 42"/>"#);
1239            serialize_as!(struct_before: AttributesBefore { key: "answer", val: 42 }
1240                => r#"<root key="answer"><val>42</val></root>"#);
1241            serialize_as!(struct_after: AttributesAfter { key: "answer", val: 42 }
1242                => r#"<root val="42"><key>answer</key></root>"#);
1243
1244            err!(enum_: Enum::Attributes { key: "answer", val: (42, 42) }
1245                => Unsupported("cannot serialize enum struct variant `Enum::Attributes`"));
1246
1247            /// Test for https://github.com/tafia/quick-xml/issues/252
1248            mod optional {
1249                use super::*;
1250                use pretty_assertions::assert_eq;
1251
1252                serialize_as!(none:
1253                    OptionalAttributes { a: None, b: None }
1254                    => r#"<root a=""/>"#);
1255                serialize_as!(some_empty_str:
1256                    OptionalAttributes {
1257                        a: Some(""),
1258                        b: Some(""),
1259                    }
1260                    => r#"<root a="" b=""/>"#);
1261                serialize_as!(some_non_empty:
1262                    OptionalAttributes {
1263                        a: Some("1"),
1264                        b: Some("2"),
1265                    }
1266                    => r#"<root a="1" b="2"/>"#);
1267            }
1268        }
1269
1270        /// Test for https://github.com/tafia/quick-xml/issues/252
1271        mod optional {
1272            use super::*;
1273            use pretty_assertions::assert_eq;
1274
1275            serialize_as!(none:
1276                OptionalElements { a: None, b: None }
1277                => "<root>\
1278                        <a/>\
1279                    </root>");
1280            serialize_as!(some_empty_str:
1281                OptionalElements {
1282                    a: Some(""),
1283                    b: Some(""),
1284                }
1285                => "<root>\
1286                        <a/>\
1287                        <b/>\
1288                    </root>");
1289            serialize_as!(some_non_empty:
1290                OptionalElements {
1291                    a: Some("1"),
1292                    b: Some("2"),
1293                }
1294                => "<root>\
1295                        <a>1</a>\
1296                        <b>2</b>\
1297                    </root>");
1298        }
1299    }
1300
1301    mod with_indent {
1302        use super::*;
1303        use crate::se::content::tests::Struct;
1304        use crate::writer::Indentation;
1305        use pretty_assertions::assert_eq;
1306
1307        /// Checks that given `$data` successfully serialized as `$expected`
1308        macro_rules! serialize_as {
1309            ($name:ident: $data:expr => $expected:expr) => {
1310                #[test]
1311                fn $name() {
1312                    let mut buffer = String::new();
1313                    let ser = ElementSerializer {
1314                        ser: ContentSerializer {
1315                            writer: &mut buffer,
1316                            level: QuoteLevel::Full,
1317                            indent: Indent::Owned(Indentation::new(b' ', 2)),
1318                            write_indent: false,
1319                            expand_empty_elements: false,
1320                        },
1321                        key: XmlName("root"),
1322                    };
1323
1324                    $data.serialize(ser).unwrap();
1325                    assert_eq!(buffer, $expected);
1326                }
1327            };
1328        }
1329
1330        /// Checks that attempt to serialize given `$data` results to a
1331        /// serialization error `$kind` with `$reason`
1332        macro_rules! err {
1333            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
1334                #[test]
1335                fn $name() {
1336                    let mut buffer = String::new();
1337                    let ser = ElementSerializer {
1338                        ser: ContentSerializer {
1339                            writer: &mut buffer,
1340                            level: QuoteLevel::Full,
1341                            indent: Indent::Owned(Indentation::new(b' ', 2)),
1342                            write_indent: false,
1343                            expand_empty_elements: false,
1344                        },
1345                        key: XmlName("root"),
1346                    };
1347
1348                    match $data.serialize(ser).unwrap_err() {
1349                        DeError::$kind(e) => assert_eq!(e, $reason),
1350                        e => panic!(
1351                            "Expected `{}({})`, found `{:?}`",
1352                            stringify!($kind),
1353                            $reason,
1354                            e
1355                        ),
1356                    }
1357                    // We can write something before fail
1358                    // assert_eq!(buffer, "");
1359                }
1360            };
1361        }
1362
1363        serialize_as!(false_: false => "<root>false</root>");
1364        serialize_as!(true_:  true  => "<root>true</root>");
1365
1366        serialize_as!(i8_:    -42i8                => "<root>-42</root>");
1367        serialize_as!(i16_:   -4200i16             => "<root>-4200</root>");
1368        serialize_as!(i32_:   -42000000i32         => "<root>-42000000</root>");
1369        serialize_as!(i64_:   -42000000000000i64   => "<root>-42000000000000</root>");
1370        serialize_as!(isize_: -42000000000000isize => "<root>-42000000000000</root>");
1371
1372        serialize_as!(u8_:    42u8                => "<root>42</root>");
1373        serialize_as!(u16_:   4200u16             => "<root>4200</root>");
1374        serialize_as!(u32_:   42000000u32         => "<root>42000000</root>");
1375        serialize_as!(u64_:   42000000000000u64   => "<root>42000000000000</root>");
1376        serialize_as!(usize_: 42000000000000usize => "<root>42000000000000</root>");
1377
1378        serde_if_integer128! {
1379            serialize_as!(i128_: -420000000000000000000000000000i128 => "<root>-420000000000000000000000000000</root>");
1380            serialize_as!(u128_:  420000000000000000000000000000u128 => "<root>420000000000000000000000000000</root>");
1381        }
1382
1383        serialize_as!(f32_: 4.2f32 => "<root>4.2</root>");
1384        serialize_as!(f64_: 4.2f64 => "<root>4.2</root>");
1385
1386        serialize_as!(char_non_escaped: 'h' => "<root>h</root>");
1387        serialize_as!(char_lt:   '<' => "<root>&lt;</root>");
1388        serialize_as!(char_gt:   '>' => "<root>&gt;</root>");
1389        serialize_as!(char_amp:  '&' => "<root>&amp;</root>");
1390        serialize_as!(char_apos: '\'' => "<root>&apos;</root>");
1391        serialize_as!(char_quot: '"' => "<root>&quot;</root>");
1392        //TODO: add a setting to escape leading/trailing spaces, in order to
1393        // pretty-print does not change the content
1394        serialize_as!(char_space: ' ' => "<root> </root>");
1395
1396        serialize_as!(str_non_escaped: "non-escaped string" => "<root>non-escaped string</root>");
1397        serialize_as!(str_escaped: "<\"escaped & string'>" => "<root>&lt;&quot;escaped &amp; string&apos;&gt;</root>");
1398
1399        err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("`serialize_bytes` not supported yet"));
1400
1401        serialize_as!(option_none: Option::<&str>::None => "<root/>");
1402        serialize_as!(option_some: Some("non-escaped string") => "<root>non-escaped string</root>");
1403        serialize_as!(option_some_empty: Some("") => "<root/>");
1404
1405        serialize_as!(unit: () => "<root/>");
1406        serialize_as!(unit_struct: Unit => "<root/>");
1407        serialize_as!(unit_struct_escaped: UnitEscaped => "<root/>");
1408
1409        serialize_as!(enum_unit: Enum::Unit => "<root>Unit</root>");
1410        serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<root>&lt;&quot;&amp;&apos;&gt;</root>");
1411
1412        serialize_as!(newtype: Newtype(42) => "<root>42</root>");
1413        err!(enum_newtype: Enum::Newtype(42)
1414            => Unsupported("cannot serialize enum newtype variant `Enum::Newtype`"));
1415
1416        serialize_as!(seq: vec![1, 2, 3]
1417            => "<root>1</root>\n\
1418                <root>2</root>\n\
1419                <root>3</root>");
1420        serialize_as!(seq_empty: Vec::<usize>::new() => "");
1421        serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1422            => "<root>&lt;&quot;&amp;&apos;&gt;</root>\n\
1423                <root>with\t\n\r spaces</root>\n\
1424                <root>3</root>");
1425        serialize_as!(tuple_struct: Tuple("first", 42)
1426            => "<root>first</root>\n\
1427                <root>42</root>");
1428        err!(enum_tuple: Enum::Tuple("first", 42)
1429            => Unsupported("cannot serialize enum tuple variant `Enum::Tuple`"));
1430
1431        serialize_as!(map: BTreeMap::from([("_1", 2), ("_3", 4)])
1432            => "<root>\n  \
1433                    <_1>2</_1>\n  \
1434                    <_3>4</_3>\n\
1435                </root>");
1436        serialize_as!(struct_: Struct { key: "answer", val: (42, 42) }
1437            => "<root>\n  \
1438                    <key>answer</key>\n  \
1439                    <val>42</val>\n  \
1440                    <val>42</val>\n\
1441                </root>");
1442        err!(enum_struct: Enum::Struct { key: "answer", val: (42, 42) }
1443            => Unsupported("cannot serialize enum struct variant `Enum::Struct`"));
1444
1445        /// Special field name `$text` should be serialized as text content.
1446        /// Sequences serialized as an `xs:list` content
1447        mod text_field {
1448            use super::*;
1449
1450            /// `$text` key in a map
1451            mod map {
1452                use super::*;
1453                use pretty_assertions::assert_eq;
1454
1455                macro_rules! text {
1456                    ($name:ident: $data:expr) => {
1457                        serialize_as!($name:
1458                            BTreeMap::from([("$text", $data)])
1459                            => "<root/>");
1460                    };
1461                    ($name:ident: $data:expr => $expected:literal) => {
1462                        serialize_as!($name:
1463                            BTreeMap::from([("$text", $data)])
1464                            => concat!("<root>\n  ", $expected,"\n</root>"));
1465                    };
1466                }
1467
1468                text!(false_: false => "false");
1469                text!(true_:  true  => "true");
1470
1471                text!(i8_:    -42i8                => "-42");
1472                text!(i16_:   -4200i16             => "-4200");
1473                text!(i32_:   -42000000i32         => "-42000000");
1474                text!(i64_:   -42000000000000i64   => "-42000000000000");
1475                text!(isize_: -42000000000000isize => "-42000000000000");
1476
1477                text!(u8_:    42u8                => "42");
1478                text!(u16_:   4200u16             => "4200");
1479                text!(u32_:   42000000u32         => "42000000");
1480                text!(u64_:   42000000000000u64   => "42000000000000");
1481                text!(usize_: 42000000000000usize => "42000000000000");
1482
1483                serde_if_integer128! {
1484                    text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1485                    text!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1486                }
1487
1488                text!(f32_: 4.2f32 => "4.2");
1489                text!(f64_: 4.2f64 => "4.2");
1490
1491                text!(char_non_escaped: 'h' => "h");
1492                text!(char_lt:   '<' => "&lt;");
1493                text!(char_gt:   '>' => "&gt;");
1494                text!(char_amp:  '&' => "&amp;");
1495                text!(char_apos: '\'' => "&apos;");
1496                text!(char_quot: '"' => "&quot;");
1497                //TODO: add a setting to escape leading/trailing spaces, in order to
1498                // pretty-print does not change the content
1499                text!(char_space: ' ' => " ");
1500
1501                text!(str_non_escaped: "non-escaped string" => "non-escaped string");
1502                text!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1503
1504                err!(bytes:
1505                    Text {
1506                        before: "answer",
1507                        content: Bytes(b"<\"escaped & bytes'>"),
1508                        after: "answer",
1509                    }
1510                    => Unsupported("`serialize_bytes` not supported yet"));
1511
1512                text!(option_none: Option::<&str>::None);
1513                text!(option_some: Some("non-escaped string") => "non-escaped string");
1514                text!(option_some_empty_str: Some(""));
1515
1516                text!(unit: ());
1517                text!(unit_struct: Unit);
1518                text!(unit_struct_escaped: UnitEscaped);
1519
1520                text!(enum_unit: Enum::Unit => "Unit");
1521                text!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
1522
1523                text!(newtype: Newtype(42) => "42");
1524                // We have no space where name of a variant can be stored
1525                err!(enum_newtype:
1526                    Text {
1527                        before: "answer",
1528                        content: Enum::Newtype(42),
1529                        after: "answer",
1530                    }
1531                    => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value"));
1532
1533                // Sequences are serialized separated by spaces, all spaces inside are escaped
1534                text!(seq: vec![1, 2, 3] => "1 2 3");
1535                text!(seq_empty: Vec::<usize>::new());
1536                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1537                    => "&lt;&quot;&amp;&apos;&gt; \
1538                        with&#9;&#10;&#13;&#32;spaces \
1539                        3");
1540                text!(tuple_struct: Tuple("first", 42) => "first 42");
1541                // We have no space where name of a variant can be stored
1542                err!(enum_tuple:
1543                    Text {
1544                        before: "answer",
1545                        content: Enum::Tuple("first", 42),
1546                        after: "answer",
1547                    }
1548                    => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value"));
1549
1550                // Complex types cannot be serialized in `$text` field
1551                err!(map:
1552                    Text {
1553                        before: "answer",
1554                        content: BTreeMap::from([("_1", 2), ("_3", 4)]),
1555                        after: "answer",
1556                    }
1557                    => Unsupported("cannot serialize map as text content value"));
1558                err!(struct_:
1559                    Text {
1560                        before: "answer",
1561                        content: Struct { key: "answer", val: (42, 42) },
1562                        after: "answer",
1563                    }
1564                    => Unsupported("cannot serialize struct `Struct` as text content value"));
1565                err!(enum_struct:
1566                    Text {
1567                        before: "answer",
1568                        content: Enum::Struct { key: "answer", val: (42, 42) },
1569                        after: "answer",
1570                    }
1571                    => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value"));
1572            }
1573
1574            /// `$text` field inside a struct
1575            mod struct_ {
1576                use super::*;
1577                use pretty_assertions::assert_eq;
1578
1579                macro_rules! text {
1580                    ($name:ident: $data:expr) => {
1581                        serialize_as!($name:
1582                            Text {
1583                                before: "answer",
1584                                content: $data,
1585                                after: "answer",
1586                            }
1587                            => "<root>\n  \
1588                                    <before>answer</before>\n  \
1589                                    <after>answer</after>\n\
1590                                </root>");
1591                    };
1592                    ($name:ident: $data:expr => $expected:literal) => {
1593                        serialize_as!($name:
1594                            Text {
1595                                before: "answer",
1596                                content: $data,
1597                                after: "answer",
1598                            }
1599                            => concat!(
1600                                "<root>\n  <before>answer</before>\n  ",
1601                                $expected,
1602                                "\n  <after>answer</after>\n</root>",
1603                            ));
1604                    };
1605                }
1606
1607                text!(false_: false => "false");
1608                text!(true_:  true  => "true");
1609
1610                text!(i8_:    -42i8                => "-42");
1611                text!(i16_:   -4200i16             => "-4200");
1612                text!(i32_:   -42000000i32         => "-42000000");
1613                text!(i64_:   -42000000000000i64   => "-42000000000000");
1614                text!(isize_: -42000000000000isize => "-42000000000000");
1615
1616                text!(u8_:    42u8                => "42");
1617                text!(u16_:   4200u16             => "4200");
1618                text!(u32_:   42000000u32         => "42000000");
1619                text!(u64_:   42000000000000u64   => "42000000000000");
1620                text!(usize_: 42000000000000usize => "42000000000000");
1621
1622                serde_if_integer128! {
1623                    text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1624                    text!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1625                }
1626
1627                text!(f32_: 4.2f32 => "4.2");
1628                text!(f64_: 4.2f64 => "4.2");
1629
1630                text!(char_non_escaped: 'h' => "h");
1631                text!(char_lt:   '<' => "&lt;");
1632                text!(char_gt:   '>' => "&gt;");
1633                text!(char_amp:  '&' => "&amp;");
1634                text!(char_apos: '\'' => "&apos;");
1635                text!(char_quot: '"' => "&quot;");
1636                //TODO: add a setting to escape leading/trailing spaces, in order to
1637                // pretty-print does not change the content
1638                text!(char_space: ' ' => " ");
1639
1640                text!(str_non_escaped: "non-escaped string" => "non-escaped string");
1641                text!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1642
1643                err!(bytes:
1644                    Text {
1645                        before: "answer",
1646                        content: Bytes(b"<\"escaped & bytes'>"),
1647                        after: "answer",
1648                    }
1649                    => Unsupported("`serialize_bytes` not supported yet"));
1650
1651                text!(option_none: Option::<&str>::None);
1652                text!(option_some: Some("non-escaped string") => "non-escaped string");
1653                text!(option_some_empty_str: Some(""));
1654
1655                text!(unit: ());
1656                text!(unit_struct: Unit);
1657                text!(unit_struct_escaped: UnitEscaped);
1658
1659                text!(enum_unit: Enum::Unit => "Unit");
1660                text!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
1661
1662                text!(newtype: Newtype(42) => "42");
1663                // We have no space where name of a variant can be stored
1664                err!(enum_newtype:
1665                    Text {
1666                        before: "answer",
1667                        content: Enum::Newtype(42),
1668                        after: "answer",
1669                    }
1670                    => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value"));
1671
1672                // Sequences are serialized separated by spaces, all spaces inside are escaped
1673                text!(seq: vec![1, 2, 3] => "1 2 3");
1674                text!(seq_empty: Vec::<usize>::new());
1675                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1676                    => "&lt;&quot;&amp;&apos;&gt; \
1677                        with&#9;&#10;&#13;&#32;spaces \
1678                        3");
1679                text!(tuple_struct: Tuple("first", 42) => "first 42");
1680                // We have no space where name of a variant can be stored
1681                err!(enum_tuple:
1682                    Text {
1683                        before: "answer",
1684                        content: Enum::Tuple("first", 42),
1685                        after: "answer",
1686                    }
1687                    => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value"));
1688
1689                // Complex types cannot be serialized in `$text` field
1690                err!(map:
1691                    Text {
1692                        before: "answer",
1693                        content: BTreeMap::from([("_1", 2), ("_3", 4)]),
1694                        after: "answer",
1695                    }
1696                    => Unsupported("cannot serialize map as text content value"));
1697                err!(struct_:
1698                    Text {
1699                        before: "answer",
1700                        content: Struct { key: "answer", val: (42, 42) },
1701                        after: "answer",
1702                    }
1703                    => Unsupported("cannot serialize struct `Struct` as text content value"));
1704                err!(enum_struct:
1705                    Text {
1706                        before: "answer",
1707                        content: Enum::Struct { key: "answer", val: (42, 42) },
1708                        after: "answer",
1709                    }
1710                    => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value"));
1711            }
1712        }
1713
1714        /// Special field name `$value` should be serialized using name, provided
1715        /// by the type of value instead of a key. Sequences serialized as a list
1716        /// of tags with that name (each element can have their own name)
1717        mod value_field {
1718            use super::*;
1719
1720            /// `$value` key in a map
1721            mod map {
1722                use super::*;
1723                use pretty_assertions::assert_eq;
1724
1725                macro_rules! value {
1726                    ($name:ident: $data:expr) => {
1727                        serialize_as!($name:
1728                            BTreeMap::from([("$value", $data)])
1729                            => "<root/>");
1730                    };
1731                    ($name:ident: $data:expr => $expected:literal) => {
1732                        serialize_as!($name:
1733                            BTreeMap::from([("$value", $data)])
1734                            => concat!("<root>\n  ", $expected,"\n</root>"));
1735                    };
1736                }
1737
1738                value!(false_: false => "false");
1739                value!(true_:  true  => "true");
1740
1741                value!(i8_:    -42i8                => "-42");
1742                value!(i16_:   -4200i16             => "-4200");
1743                value!(i32_:   -42000000i32         => "-42000000");
1744                value!(i64_:   -42000000000000i64   => "-42000000000000");
1745                value!(isize_: -42000000000000isize => "-42000000000000");
1746
1747                value!(u8_:    42u8                => "42");
1748                value!(u16_:   4200u16             => "4200");
1749                value!(u32_:   42000000u32         => "42000000");
1750                value!(u64_:   42000000000000u64   => "42000000000000");
1751                value!(usize_: 42000000000000usize => "42000000000000");
1752
1753                serde_if_integer128! {
1754                    value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1755                    value!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1756                }
1757
1758                value!(f32_: 4.2f32 => "4.2");
1759                value!(f64_: 4.2f64 => "4.2");
1760
1761                value!(char_non_escaped: 'h' => "h");
1762                value!(char_lt:   '<' => "&lt;");
1763                value!(char_gt:   '>' => "&gt;");
1764                value!(char_amp:  '&' => "&amp;");
1765                value!(char_apos: '\'' => "&apos;");
1766                value!(char_quot: '"' => "&quot;");
1767                //TODO: add a setting to escape leading/trailing spaces, in order to
1768                // pretty-print does not change the content
1769                value!(char_space: ' ' => " ");
1770
1771                value!(str_non_escaped: "non-escaped string" => "non-escaped string");
1772                value!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1773
1774                err!(bytes:
1775                    BTreeMap::from([("$value", Bytes(b"<\"escaped & bytes'>"))])
1776                    => Unsupported("`serialize_bytes` not supported yet"));
1777
1778                value!(option_none: Option::<&str>::None);
1779                value!(option_some: Some("non-escaped string") => "non-escaped string");
1780                value!(option_some_empty_str: Some(""));
1781
1782                value!(unit: ());
1783                value!(unit_struct: Unit);
1784                value!(unit_struct_escaped: UnitEscaped);
1785
1786                value!(enum_unit: Enum::Unit => "<Unit/>");
1787                err!(enum_unit_escaped:
1788                    BTreeMap::from([("$value", Enum::UnitEscaped)])
1789                    => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
1790
1791                value!(newtype: Newtype(42) => "42");
1792                value!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>");
1793
1794                value!(seq: vec![1, 2, 3] => "1\n  2\n  3");
1795                value!(seq_empty: Vec::<usize>::new());
1796                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1797                    => "&lt;&quot;&amp;&apos;&gt;\n  \
1798                        with\t\n\r spaces\n  \
1799                        3");
1800                value!(tuple_struct: Tuple("first", 42) => "first\n  42");
1801                value!(enum_tuple: Enum::Tuple("first", 42)
1802                    => "<Tuple>first</Tuple>\n  \
1803                        <Tuple>42</Tuple>");
1804
1805                // We cannot wrap map or struct in any container and should not
1806                // flatten it, so it is impossible to serialize maps and structs
1807                err!(map:
1808                    BTreeMap::from([("$value", BTreeMap::from([("_1", 2), ("_3", 4)]))])
1809                    => Unsupported("serialization of map types is not supported in `$value` field"));
1810                err!(struct_:
1811                    BTreeMap::from([("$value", Struct { key: "answer", val: (42, 42) })])
1812                    => Unsupported("serialization of struct `Struct` is not supported in `$value` field"));
1813                value!(enum_struct:
1814                    Enum::Struct { key: "answer", val: (42, 42) }
1815                    => "<Struct>\n    \
1816                            <key>answer</key>\n    \
1817                            <val>42</val>\n    \
1818                            <val>42</val>\n  \
1819                        </Struct>");
1820            }
1821
1822            /// `$value` field inside a struct
1823            mod struct_ {
1824                use super::*;
1825                use pretty_assertions::assert_eq;
1826
1827                macro_rules! value {
1828                    ($name:ident: $data:expr) => {
1829                        serialize_as!($name:
1830                            Value {
1831                                before: "answer",
1832                                content: $data,
1833                                after: "answer",
1834                            }
1835                            => "<root>\n  \
1836                                    <before>answer</before>\n  \
1837                                    <after>answer</after>\n\
1838                                </root>");
1839                    };
1840                    ($name:ident: $data:expr => $expected:literal) => {
1841                        serialize_as!($name:
1842                            Value {
1843                                before: "answer",
1844                                content: $data,
1845                                after: "answer",
1846                            }
1847                            => concat!(
1848                                "<root>\n  <before>answer</before>\n  ",
1849                                $expected,
1850                                "\n  <after>answer</after>\n</root>",
1851                            ));
1852                    };
1853                }
1854
1855                value!(false_: false => "false");
1856                value!(true_:  true  => "true");
1857
1858                value!(i8_:    -42i8                => "-42");
1859                value!(i16_:   -4200i16             => "-4200");
1860                value!(i32_:   -42000000i32         => "-42000000");
1861                value!(i64_:   -42000000000000i64   => "-42000000000000");
1862                value!(isize_: -42000000000000isize => "-42000000000000");
1863
1864                value!(u8_:    42u8                => "42");
1865                value!(u16_:   4200u16             => "4200");
1866                value!(u32_:   42000000u32         => "42000000");
1867                value!(u64_:   42000000000000u64   => "42000000000000");
1868                value!(usize_: 42000000000000usize => "42000000000000");
1869
1870                serde_if_integer128! {
1871                    value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1872                    value!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1873                }
1874
1875                value!(f32_: 4.2f32 => "4.2");
1876                value!(f64_: 4.2f64 => "4.2");
1877
1878                value!(char_non_escaped: 'h' => "h");
1879                value!(char_lt:   '<' => "&lt;");
1880                value!(char_gt:   '>' => "&gt;");
1881                value!(char_amp:  '&' => "&amp;");
1882                value!(char_apos: '\'' => "&apos;");
1883                value!(char_quot: '"' => "&quot;");
1884                //TODO: add a setting to escape leading/trailing spaces, in order to
1885                // pretty-print does not change the content
1886                value!(char_space: ' ' => " ");
1887
1888                value!(str_non_escaped: "non-escaped string" => "non-escaped string");
1889                value!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1890
1891                err!(bytes:
1892                    Value {
1893                        before: "answer",
1894                        content: Bytes(b"<\"escaped & bytes'>"),
1895                        after: "answer",
1896                    }
1897                    => Unsupported("`serialize_bytes` not supported yet"));
1898
1899                value!(option_none: Option::<&str>::None);
1900                value!(option_some: Some("non-escaped string") => "non-escaped string");
1901                value!(option_some_empty_str: Some(""));
1902
1903                value!(unit: ());
1904                value!(unit_struct: Unit);
1905                value!(unit_struct_escaped: UnitEscaped);
1906
1907                value!(enum_unit: Enum::Unit => "<Unit/>");
1908                err!(enum_unit_escaped:
1909                    Value {
1910                        before: "answer",
1911                        content: Enum::UnitEscaped,
1912                        after: "answer",
1913                    }
1914                    => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
1915
1916                value!(newtype: Newtype(42) => "42");
1917                value!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>");
1918
1919                // Note that sequences of primitives serialized without delimiters!
1920                value!(seq: vec![1, 2, 3] => "1\n  2\n  3");
1921                value!(seq_empty: Vec::<usize>::new());
1922                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1923                    => "&lt;&quot;&amp;&apos;&gt;\n  \
1924                        with\t\n\r spaces\n  \
1925                        3");
1926                value!(tuple_struct: Tuple("first", 42) => "first\n  42");
1927                value!(enum_tuple: Enum::Tuple("first", 42)
1928                    => "<Tuple>first</Tuple>\n  \
1929                        <Tuple>42</Tuple>");
1930
1931                // We cannot wrap map or struct in any container and should not
1932                // flatten it, so it is impossible to serialize maps and structs
1933                err!(map:
1934                    Value {
1935                        before: "answer",
1936                        content: BTreeMap::from([("_1", 2), ("_3", 4)]),
1937                        after: "answer",
1938                    }
1939                    => Unsupported("serialization of map types is not supported in `$value` field"));
1940                err!(struct_:
1941                    Value {
1942                        before: "answer",
1943                        content: Struct { key: "answer", val: (42, 42) },
1944                        after: "answer",
1945                    }
1946                    => Unsupported("serialization of struct `Struct` is not supported in `$value` field"));
1947                value!(enum_struct:
1948                    Enum::Struct { key: "answer", val: (42, 42) }
1949                    => "<Struct>\n    \
1950                            <key>answer</key>\n    \
1951                            <val>42</val>\n    \
1952                            <val>42</val>\n  \
1953                        </Struct>");
1954            }
1955        }
1956
1957        mod attributes {
1958            use super::*;
1959            use pretty_assertions::assert_eq;
1960
1961            serialize_as!(map_attr: BTreeMap::from([("@key1", 1), ("@key2", 2)])
1962                => r#"<root key1="1" key2="2"/>"#);
1963            serialize_as!(map_mixed: BTreeMap::from([("@key1", 1), ("key2", 2)])
1964                => "<root key1=\"1\">\n  \
1965                        <key2>2</key2>\n\
1966                    </root>");
1967
1968            serialize_as!(struct_: Attributes { key: "answer", val: (42, 42) }
1969                => r#"<root key="answer" val="42 42"/>"#);
1970            serialize_as!(struct_before: AttributesBefore { key: "answer", val: 42 }
1971                => "<root key=\"answer\">\n  \
1972                        <val>42</val>\n\
1973                    </root>");
1974            serialize_as!(struct_after: AttributesAfter { key: "answer", val: 42 }
1975                => "<root val=\"42\">\n  \
1976                        <key>answer</key>\n\
1977                    </root>");
1978
1979            err!(enum_: Enum::Attributes { key: "answer", val: (42, 42) }
1980                => Unsupported("cannot serialize enum struct variant `Enum::Attributes`"));
1981
1982            /// Test for https://github.com/tafia/quick-xml/issues/252
1983            mod optional {
1984                use super::*;
1985                use pretty_assertions::assert_eq;
1986
1987                serialize_as!(none:
1988                    OptionalAttributes { a: None, b: None }
1989                    => r#"<root a=""/>"#);
1990                serialize_as!(some_empty_str:
1991                    OptionalAttributes {
1992                        a: Some(""),
1993                        b: Some("")
1994                    }
1995                    => r#"<root a="" b=""/>"#);
1996                serialize_as!(some_non_empty:
1997                    OptionalAttributes {
1998                        a: Some("a"),
1999                        b: Some("b")
2000                    }
2001                    => r#"<root a="a" b="b"/>"#);
2002            }
2003        }
2004
2005        /// Test for https://github.com/tafia/quick-xml/issues/252
2006        mod optional {
2007            use super::*;
2008            use pretty_assertions::assert_eq;
2009
2010            serialize_as!(none:
2011                OptionalElements { a: None, b: None }
2012                => "<root>\n  \
2013                        <a/>\n\
2014                    </root>");
2015            serialize_as!(some_empty_str:
2016                OptionalElements {
2017                    a: Some(""),
2018                    b: Some("")
2019                }
2020                => "<root>\n  \
2021                        <a/>\n  \
2022                        <b/>\n\
2023                    </root>");
2024            serialize_as!(some_non_empty:
2025                OptionalElements {
2026                    a: Some("a"),
2027                    b: Some("b")
2028                }
2029                => "<root>\n  \
2030                        <a>a</a>\n  \
2031                        <b>b</b>\n\
2032                    </root>");
2033        }
2034    }
2035
2036    mod expand_empty_elements {
2037        use super::*;
2038        use pretty_assertions::assert_eq;
2039
2040        /// Checks that given `$data` successfully serialized as `$expected`
2041        macro_rules! serialize_as {
2042            ($name:ident: $data:expr => $expected:expr) => {
2043                #[test]
2044                fn $name() {
2045                    let mut buffer = String::new();
2046                    let ser = ElementSerializer {
2047                        ser: ContentSerializer {
2048                            writer: &mut buffer,
2049                            level: QuoteLevel::Full,
2050                            indent: Indent::None,
2051                            write_indent: false,
2052                            expand_empty_elements: true,
2053                        },
2054                        key: XmlName("root"),
2055                    };
2056
2057                    $data.serialize(ser).unwrap();
2058                    assert_eq!(buffer, $expected);
2059                }
2060            };
2061        }
2062
2063        serialize_as!(option_some_empty: Some("") => "<root></root>");
2064        serialize_as!(option_some_empty_str: Some("") => "<root></root>");
2065
2066        serialize_as!(unit: () => "<root></root>");
2067        serialize_as!(unit_struct: Unit => "<root></root>");
2068        serialize_as!(unit_struct_escaped: UnitEscaped => "<root></root>");
2069
2070        serialize_as!(enum_unit: Enum::Unit => "<root>Unit</root>");
2071        serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<root>&lt;&quot;&amp;&apos;&gt;</root>");
2072    }
2073}