Skip to main content

quick_xml/se/
content.rs

1//! Contains serializer for content of an XML element
2
3use crate::de::TEXT_KEY;
4use crate::se::element::{ElementSerializer, Struct, Tuple};
5use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
6use crate::se::{
7    EmptyElementHandling, Indent, QuoteLevel, SeError, TextFormat, WriteResult, XmlName,
8};
9use serde::ser::{
10    Impossible, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct, Serializer,
11};
12use std::fmt::Write;
13
14macro_rules! write_primitive {
15    ($method:ident ( $ty:ty )) => {
16        #[inline]
17        fn $method(self, value: $ty) -> Result<Self::Ok, Self::Error> {
18            self.into_simple_type_serializer()?.$method(value)?;
19            Ok(WriteResult::Text)
20        }
21    };
22}
23
24////////////////////////////////////////////////////////////////////////////////////////////////////
25
26/// A serializer used to serialize content of an element. It does not write
27/// surrounding tags. Unlike the [`ElementSerializer`], this serializer serializes
28/// enums using variant names as tag names, i. e. as `<variant>...</variant>`.
29///
30/// Returns the classification of the last written type.
31///
32/// This serializer does the following:
33/// - numbers converted to a decimal representation and serialized as naked strings;
34/// - booleans serialized ether as `"true"` or `"false"`;
35/// - strings and characters are serialized as naked strings;
36/// - `None` does not write anything;
37/// - `Some` and newtypes are serialized as an inner type using the same serializer;
38/// - units (`()`) and unit structs does not write anything;
39/// - sequences, tuples and tuple structs are serialized without delimiters.
40///   `[1, 2, 3]` would be serialized as `123` (if not using indent);
41/// - structs and maps are not supported ([`SeError::Unsupported`] is returned);
42/// - enums:
43///   - unit variants are serialized as self-closed `<variant/>`;
44///   - newtype variants are serialized as inner value wrapped in `<variant>...</variant>`;
45///   - tuple variants are serialized as sequences where each element is wrapped
46///     in `<variant>...</variant>`;
47///   - struct variants are serialized as a sequence of fields wrapped in
48///     `<variant>...</variant>`. Each field is serialized recursively using
49///     either [`ElementSerializer`], `ContentSerializer` (`$value` fields), or
50///     [`SimpleTypeSerializer`] (`$text` fields). In particular, the empty struct
51///     is serialized as `<variant/>`;
52///
53/// Usage of empty tags depends on the [`Self::empty_element_handling`] setting.
54///
55/// The difference between this serializer and [`SimpleTypeSerializer`] is in how
56/// sequences and maps are serialized. Unlike `SimpleTypeSerializer` it supports
57/// any types in sequences and serializes them as list of elements, but that has
58/// drawbacks. Sequence of primitives would be serialized without delimiters and
59/// it will be impossible to distinguish between them. Even worse, when serializing
60/// with indent, sequence of strings become one big string with additional content
61/// and it would be impossible to distinguish between content of the original
62/// strings and inserted indent characters.
63pub struct ContentSerializer<'w, 'i, W: Write> {
64    pub writer: &'w mut W,
65    /// Defines which XML characters need to be escaped in text content
66    pub level: QuoteLevel,
67    /// Current indentation level. Note, that `Indent::None` means that there is
68    /// no indentation at all, but `write_indent == false` means only, that indent
69    /// writing is disabled in this instantiation of `ContentSerializer`, but
70    /// child serializers should have access to the actual state of indentation.
71    pub(super) indent: Indent<'i>,
72    /// If `true`, then current indent will be written before writing the content,
73    /// but only if content is not empty. This flag is reset after writing indent.
74    pub write_indent: bool,
75    /// Defines how text content should be serialized (as escaped text or CDATA)
76    pub text_format: TextFormat,
77    /// If `true`, then primitive types that serializes to a text content without
78    /// surrounding tag will be allowed, otherwise the [`SeError::Unsupported`]
79    /// will be returned.
80    ///
81    /// This method protects from the situation when two consequent values serialized
82    /// as a text that makes it impossible to distinguish between them during
83    /// deserialization. Instead of ambiguous serialization the error is returned.
84    pub allow_primitive: bool,
85    /// Specifies how empty elements are written.
86    pub empty_element_handling: EmptyElementHandling,
87}
88
89impl<'w, 'i, W: Write> ContentSerializer<'w, 'i, W> {
90    /// Turns this serializer into serializer of a text content
91    #[inline]
92    pub fn into_simple_type_serializer_impl(self) -> SimpleTypeSerializer<&'w mut W> {
93        SimpleTypeSerializer {
94            writer: self.writer,
95            target: match self.text_format {
96                TextFormat::Text => QuoteTarget::Text,
97                TextFormat::CData => QuoteTarget::CData,
98            },
99            level: self.level,
100        }
101    }
102
103    /// Turns this serializer into serializer of a text content if that is allowed,
104    /// otherwise error is returned
105    #[inline]
106    pub fn into_simple_type_serializer(self) -> Result<SimpleTypeSerializer<&'w mut W>, SeError> {
107        if self.allow_primitive {
108            Ok(self.into_simple_type_serializer_impl())
109        } else {
110            Err(SeError::Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back".into()))
111        }
112    }
113
114    /// Creates new serializer that shares state with this serializer and
115    /// writes to the same underlying writer
116    #[inline]
117    pub fn new_seq_element_serializer(
118        &mut self,
119        allow_primitive: bool,
120    ) -> ContentSerializer<'_, '_, W> {
121        ContentSerializer {
122            writer: self.writer,
123            level: self.level,
124            indent: self.indent.borrow(),
125            write_indent: self.write_indent,
126            text_format: self.text_format,
127            allow_primitive,
128            empty_element_handling: self.empty_element_handling,
129        }
130    }
131
132    /// Writes `name` as self-closed tag
133    #[inline]
134    pub(super) fn write_empty(mut self, name: XmlName) -> Result<WriteResult, SeError> {
135        self.write_indent()?;
136
137        match self.empty_element_handling {
138            EmptyElementHandling::SelfClosed => {
139                self.writer.write_char('<')?;
140                self.writer.write_str(name.0)?;
141                self.writer.write_str("/>")?;
142            }
143            EmptyElementHandling::SelfClosedWithSpace => {
144                self.writer.write_char('<')?;
145                self.writer.write_str(name.0)?;
146                self.writer.write_str(" />")?;
147            }
148            EmptyElementHandling::Expanded => {
149                self.writer.write_char('<')?;
150                self.writer.write_str(name.0)?;
151                self.writer.write_str("></")?;
152                self.writer.write_str(name.0)?;
153                self.writer.write_char('>')?;
154            }
155        }
156
157        Ok(WriteResult::Element)
158    }
159
160    /// Writes simple type content between `name` tags
161    pub(super) fn write_wrapped<S>(
162        mut self,
163        name: XmlName,
164        serialize: S,
165    ) -> Result<WriteResult, SeError>
166    where
167        S: for<'a> FnOnce(SimpleTypeSerializer<&'a mut W>) -> Result<&'a mut W, SeError>,
168    {
169        self.write_indent()?;
170        self.writer.write_char('<')?;
171        self.writer.write_str(name.0)?;
172        self.writer.write_char('>')?;
173
174        let writer = serialize(self.into_simple_type_serializer_impl())?;
175
176        writer.write_str("</")?;
177        writer.write_str(name.0)?;
178        writer.write_char('>')?;
179        Ok(WriteResult::Element)
180    }
181
182    pub(super) fn write_indent(&mut self) -> Result<(), SeError> {
183        if self.write_indent {
184            self.indent.write_indent(&mut self.writer)?;
185            self.write_indent = false;
186        }
187        Ok(())
188    }
189}
190
191impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
192    type Ok = WriteResult;
193    type Error = SeError;
194
195    type SerializeSeq = Seq<'w, 'i, W>;
196    type SerializeTuple = Seq<'w, 'i, W>;
197    type SerializeTupleStruct = Seq<'w, 'i, W>;
198    type SerializeTupleVariant = Tuple<'w, 'i, W>;
199    type SerializeMap = Impossible<Self::Ok, Self::Error>;
200    type SerializeStruct = Struct<'w, 'i, W>;
201    type SerializeStructVariant = Struct<'w, 'i, W>;
202
203    write_primitive!(serialize_bool(bool));
204
205    write_primitive!(serialize_i8(i8));
206    write_primitive!(serialize_i16(i16));
207    write_primitive!(serialize_i32(i32));
208    write_primitive!(serialize_i64(i64));
209
210    write_primitive!(serialize_u8(u8));
211    write_primitive!(serialize_u16(u16));
212    write_primitive!(serialize_u32(u32));
213    write_primitive!(serialize_u64(u64));
214
215    write_primitive!(serialize_i128(i128));
216    write_primitive!(serialize_u128(u128));
217
218    write_primitive!(serialize_f32(f32));
219    write_primitive!(serialize_f64(f64));
220
221    write_primitive!(serialize_bytes(&[u8]));
222
223    #[inline]
224    fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
225        self.into_simple_type_serializer()?.serialize_char(value)?;
226        Ok(WriteResult::SensitiveText)
227    }
228
229    #[inline]
230    fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
231        if !value.is_empty() {
232            self.into_simple_type_serializer()?.serialize_str(value)?;
233        }
234        Ok(WriteResult::SensitiveText)
235    }
236
237    /// Does not write anything
238    #[inline]
239    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
240        // Classify `None` as sensitive to whitespaces, because this can be `Option<String>`.
241        // Unfortunately, we do not known what the type the option contains, so have no chance
242        // to adapt our behavior to it. The safe variant is assume sensitiviness
243        Ok(WriteResult::SensitiveNothing)
244    }
245
246    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
247        value.serialize(self)
248    }
249
250    /// Does not write anything
251    #[inline]
252    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
253        Ok(WriteResult::Nothing)
254    }
255
256    /// Does not write anything
257    #[inline]
258    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
259        Ok(WriteResult::Nothing)
260    }
261
262    /// If `variant` is a special `$text` variant, then do nothing, otherwise
263    /// checks `variant` for XML name validity and writes `<variant/>`.
264    fn serialize_unit_variant(
265        self,
266        _name: &'static str,
267        _variant_index: u32,
268        variant: &'static str,
269    ) -> Result<Self::Ok, Self::Error> {
270        if variant == TEXT_KEY {
271            Ok(WriteResult::Nothing)
272        } else {
273            let name = XmlName::try_from(variant)?;
274            self.write_empty(name)
275        }
276    }
277
278    fn serialize_newtype_struct<T: ?Sized + Serialize>(
279        self,
280        _name: &'static str,
281        value: &T,
282    ) -> Result<Self::Ok, Self::Error> {
283        value.serialize(self)
284    }
285
286    /// If `variant` is a special `$text` variant, then writes `value` as a `xs:simpleType`,
287    /// otherwise checks `variant` for XML name validity and writes `value` as a new
288    /// `<variant>` element.
289    fn serialize_newtype_variant<T: ?Sized + Serialize>(
290        self,
291        _name: &'static str,
292        _variant_index: u32,
293        variant: &'static str,
294        value: &T,
295    ) -> Result<Self::Ok, Self::Error> {
296        if variant == TEXT_KEY {
297            value.serialize(self.into_simple_type_serializer()?)?;
298            Ok(WriteResult::SensitiveText)
299        } else {
300            value.serialize(ElementSerializer {
301                key: XmlName::try_from(variant)?,
302                ser: self,
303            })?;
304            Ok(WriteResult::Element)
305        }
306    }
307
308    #[inline]
309    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
310        Ok(Seq {
311            ser: self,
312            // If sequence if empty, nothing will be serialized. Because sequence can be of `Option`s
313            // we need to assume that writing indent may change the data and do not write anything
314            last: WriteResult::SensitiveNothing,
315        })
316    }
317
318    #[inline]
319    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
320        self.serialize_seq(Some(len))
321    }
322
323    #[inline]
324    fn serialize_tuple_struct(
325        self,
326        _name: &'static str,
327        len: usize,
328    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
329        self.serialize_tuple(len)
330    }
331
332    /// Serializes variant as a tuple with name `variant`, producing
333    ///
334    /// ```xml
335    /// <variant><!-- 1st element of a tuple --></variant>
336    /// <variant><!-- 2nd element of a tuple --></variant>
337    /// <!-- ... -->
338    /// <variant><!-- Nth element of a tuple --></variant>
339    /// ```
340    #[inline]
341    fn serialize_tuple_variant(
342        self,
343        name: &'static str,
344        _variant_index: u32,
345        variant: &'static str,
346        len: usize,
347    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
348        if variant == TEXT_KEY {
349            self.into_simple_type_serializer()?
350                .serialize_tuple_struct(name, len)
351                .map(Tuple::Text)
352        } else {
353            let ser = ElementSerializer {
354                key: XmlName::try_from(variant)?,
355                ser: self,
356            };
357            ser.serialize_tuple_struct(name, len).map(Tuple::Element)
358        }
359    }
360
361    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
362        Err(SeError::Unsupported(
363            "serialization of map types is not supported in `$value` field".into(),
364        ))
365    }
366
367    #[inline]
368    fn serialize_struct(
369        self,
370        name: &'static str,
371        len: usize,
372    ) -> Result<Self::SerializeStruct, Self::Error> {
373        ElementSerializer {
374            ser: self,
375            key: XmlName::try_from(name)?,
376        }
377        .serialize_struct(name, len)
378    }
379
380    /// Serializes variant as an element with name `variant`, producing
381    ///
382    /// ```xml
383    /// <variant>
384    ///   <!-- struct fields... -->
385    /// </variant>
386    /// ```
387    ///
388    /// If struct has no fields which is represented by nested elements or a text,
389    /// it may be serialized as self-closed element `<variant/>`.
390    #[inline]
391    fn serialize_struct_variant(
392        self,
393        name: &'static str,
394        _variant_index: u32,
395        variant: &'static str,
396        len: usize,
397    ) -> Result<Self::SerializeStructVariant, Self::Error> {
398        if variant == TEXT_KEY {
399            Err(SeError::Unsupported(
400                format!("cannot serialize `$text` struct variant of `{}` enum", name).into(),
401            ))
402        } else {
403            let ser = ElementSerializer {
404                key: XmlName::try_from(variant)?,
405                ser: self,
406            };
407            ser.serialize_struct(name, len)
408        }
409    }
410}
411
412////////////////////////////////////////////////////////////////////////////////////////////////////
413
414/// Helper struct which remembers the classification of the last serialized element
415/// and reports it when the sequence ends
416pub struct Seq<'w, 'k, W: Write> {
417    ser: ContentSerializer<'w, 'k, W>,
418    /// Classification of the result of the last serialized element.
419    last: WriteResult,
420}
421
422impl<'w, 'i, W: Write> SerializeSeq for Seq<'w, 'i, W> {
423    type Ok = WriteResult;
424    type Error = SeError;
425
426    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
427    where
428        T: ?Sized + Serialize,
429    {
430        self.last = value.serialize(self.ser.new_seq_element_serializer(self.last.is_text()))?;
431        // Write indent for next element if indents are used
432        self.ser.write_indent = self.last.allow_indent();
433        Ok(())
434    }
435
436    #[inline]
437    fn end(self) -> Result<Self::Ok, Self::Error> {
438        Ok(self.last)
439    }
440}
441
442impl<'w, 'i, W: Write> SerializeTuple for Seq<'w, 'i, W> {
443    type Ok = WriteResult;
444    type Error = SeError;
445
446    #[inline]
447    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
448    where
449        T: ?Sized + Serialize,
450    {
451        SerializeSeq::serialize_element(self, value)
452    }
453
454    #[inline]
455    fn end(self) -> Result<Self::Ok, Self::Error> {
456        SerializeSeq::end(self)
457    }
458}
459
460impl<'w, 'i, W: Write> SerializeTupleStruct for Seq<'w, 'i, W> {
461    type Ok = WriteResult;
462    type Error = SeError;
463
464    #[inline]
465    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
466    where
467        T: ?Sized + Serialize,
468    {
469        SerializeSeq::serialize_element(self, value)
470    }
471
472    #[inline]
473    fn end(self) -> Result<Self::Ok, Self::Error> {
474        SerializeSeq::end(self)
475    }
476}
477
478////////////////////////////////////////////////////////////////////////////////////////////////////
479
480/// Make tests public to reuse types in `elements::tests` module
481#[cfg(test)]
482pub(super) mod tests {
483    use super::*;
484    use crate::utils::Bytes;
485    use serde::Serialize;
486    use std::collections::BTreeMap;
487    use WriteResult::*;
488
489    #[derive(Debug, Serialize, PartialEq)]
490    pub struct Unit;
491
492    #[derive(Debug, Serialize, PartialEq)]
493    #[serde(rename = "<\"&'>")]
494    pub struct UnitEscaped;
495
496    #[derive(Debug, Serialize, PartialEq)]
497    pub struct Newtype(pub usize);
498
499    #[derive(Debug, Serialize, PartialEq)]
500    pub struct Tuple(pub &'static str, pub usize);
501
502    #[derive(Debug, Serialize, PartialEq)]
503    pub struct Struct {
504        pub key: &'static str,
505        pub val: (usize, usize),
506    }
507
508    /// Struct with a special `$text` field
509    #[derive(Debug, Serialize, PartialEq)]
510    pub struct Text<T> {
511        pub before: &'static str,
512        #[serde(rename = "$text")]
513        pub content: T,
514        pub after: &'static str,
515    }
516
517    /// Struct with a special `$value` field
518    #[derive(Debug, Serialize, PartialEq)]
519    pub struct Value<T> {
520        pub before: &'static str,
521        #[serde(rename = "$value")]
522        pub content: T,
523        pub after: &'static str,
524    }
525
526    /// Attributes identified by starting with `@` character
527    #[derive(Debug, Serialize, PartialEq)]
528    pub struct Attributes {
529        #[serde(rename = "@key")]
530        pub key: &'static str,
531        #[serde(rename = "@val")]
532        pub val: (usize, usize),
533    }
534    #[derive(Debug, Serialize, PartialEq)]
535    pub struct AttributesBefore {
536        #[serde(rename = "@key")]
537        pub key: &'static str,
538        pub val: usize,
539    }
540    #[derive(Debug, Serialize, PartialEq)]
541    pub struct AttributesAfter {
542        pub key: &'static str,
543        #[serde(rename = "@val")]
544        pub val: usize,
545    }
546
547    #[derive(Debug, Serialize, PartialEq)]
548    pub enum Enum {
549        Unit,
550        /// Variant name becomes a tag name, but the name of variant is invalid
551        /// XML name. Serialization of this element should be forbidden
552        #[serde(rename = "<\"&'>")]
553        UnitEscaped,
554        Newtype(usize),
555        Tuple(&'static str, usize),
556        Struct {
557            key: &'static str,
558            /// Should be serialized as elements
559            val: (usize, usize),
560        },
561        Attributes {
562            #[serde(rename = "@key")]
563            key: &'static str,
564            #[serde(rename = "@val")]
565            val: (usize, usize),
566        },
567        AttributesBefore {
568            #[serde(rename = "@key")]
569            key: &'static str,
570            val: usize,
571        },
572        AttributesAfter {
573            key: &'static str,
574            #[serde(rename = "@val")]
575            val: usize,
576        },
577    }
578
579    #[derive(Debug, Serialize, PartialEq)]
580    pub enum SpecialEnum<T> {
581        /// Struct variant with a special `$text` field
582        Text {
583            before: &'static str,
584            #[serde(rename = "$text")]
585            content: T,
586            after: &'static str,
587        },
588        /// Struct variant with a special `$value` field
589        Value {
590            before: &'static str,
591            #[serde(rename = "$value")]
592            content: T,
593            after: &'static str,
594        },
595    }
596
597    mod without_indent {
598        use super::Struct;
599        use super::*;
600        use pretty_assertions::assert_eq;
601
602        /// Checks that given `$data` successfully serialized as `$expected`
603        macro_rules! serialize_as {
604            ($name:ident: $data:expr => $expected:expr) => {
605                serialize_as!($name: $data => $expected, WriteResult::Element);
606            };
607            ($name:ident: $data:expr => $expected:expr, $result:expr) => {
608                #[test]
609                fn $name() {
610                    let mut buffer = String::new();
611                    let ser = ContentSerializer {
612                        writer: &mut buffer,
613                        level: QuoteLevel::Full,
614                        indent: Indent::None,
615                        write_indent: false,
616                        text_format: TextFormat::Text,
617                        allow_primitive: true,
618                        empty_element_handling: EmptyElementHandling::SelfClosed,
619                    };
620
621                    let result = $data.serialize(ser).unwrap();
622                    assert_eq!(buffer, $expected);
623                    assert_eq!(result, $result);
624                }
625            };
626        }
627
628        /// Checks that attempt to serialize given `$data` results to a
629        /// serialization error `$kind` with `$reason`
630        macro_rules! err {
631            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
632                #[test]
633                fn $name() {
634                    let mut buffer = String::new();
635                    let ser = ContentSerializer {
636                        writer: &mut buffer,
637                        level: QuoteLevel::Full,
638                        indent: Indent::None,
639                        write_indent: false,
640                        text_format: TextFormat::Text,
641                        allow_primitive: true,
642                        empty_element_handling: EmptyElementHandling::SelfClosed,
643                    };
644
645                    match $data.serialize(ser).unwrap_err() {
646                        SeError::$kind(e) => assert_eq!(e, $reason),
647                        e => panic!(
648                            "Expected `Err({}({}))`, but got `{:?}`",
649                            stringify!($kind),
650                            $reason,
651                            e
652                        ),
653                    }
654                    // We could write something before fail
655                    // assert_eq!(buffer, "");
656                }
657            };
658        }
659
660        // Primitives is serialized in the same way as for SimpleTypeSerializer
661        serialize_as!(false_: false => "false", Text);
662        serialize_as!(true_:  true  => "true", Text);
663
664        serialize_as!(i8_:    -42i8                => "-42", Text);
665        serialize_as!(i16_:   -4200i16             => "-4200", Text);
666        serialize_as!(i32_:   -42000000i32         => "-42000000", Text);
667        serialize_as!(i64_:   -42000000000000i64   => "-42000000000000", Text);
668        serialize_as!(isize_: -42000000isize       => "-42000000", Text);
669
670        serialize_as!(u8_:    42u8                => "42", Text);
671        serialize_as!(u16_:   4200u16             => "4200", Text);
672        serialize_as!(u32_:   42000000u32         => "42000000", Text);
673        serialize_as!(u64_:   42000000000000u64   => "42000000000000", Text);
674        serialize_as!(usize_: 42000000usize       => "42000000", Text);
675
676        serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000", Text);
677        serialize_as!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000", Text);
678
679        serialize_as!(f32_: 4.2f32 => "4.2", Text);
680        serialize_as!(f64_: 4.2f64 => "4.2", Text);
681
682        serialize_as!(char_non_escaped: 'h' => "h", SensitiveText);
683        serialize_as!(char_lt:   '<' => "&lt;", SensitiveText);
684        serialize_as!(char_gt:   '>' => "&gt;", SensitiveText);
685        serialize_as!(char_amp:  '&' => "&amp;", SensitiveText);
686        serialize_as!(char_apos: '\'' => "&apos;", SensitiveText);
687        serialize_as!(char_quot: '"' => "&quot;", SensitiveText);
688        serialize_as!(char_space: ' ' => " ", SensitiveText);
689
690        serialize_as!(str_non_escaped: "non-escaped string" => "non-escaped string", SensitiveText);
691        serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;", SensitiveText);
692
693        err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("`serialize_bytes` not supported yet"));
694
695        serialize_as!(option_none: Option::<Enum>::None => "", SensitiveNothing);
696        serialize_as!(option_some: Some("non-escaped string") => "non-escaped string", SensitiveText);
697        serialize_as!(option_some_empty_str: Some("") => "", SensitiveText);
698
699        serialize_as!(unit: () => "", Nothing);
700        serialize_as!(unit_struct: Unit => "", Nothing);
701        serialize_as!(unit_struct_escaped: UnitEscaped => "", Nothing);
702
703        // Unlike SimpleTypeSerializer, enumeration values serialized as tags
704        serialize_as!(enum_unit: Enum::Unit => "<Unit/>");
705        err!(enum_unit_escaped: Enum::UnitEscaped
706            => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
707
708        // Newtypes recursively applies ContentSerializer
709        serialize_as!(newtype: Newtype(42) => "42", Text);
710        serialize_as!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>");
711
712        // Note that sequences of primitives serialized without delimiters!
713        err!(seq: vec![1, 2, 3]
714            => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
715        serialize_as!(seq_empty: Vec::<usize>::new() => "", SensitiveNothing);
716        err!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
717            => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
718        err!(tuple_struct: Tuple("first", 42)
719            => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
720        serialize_as!(enum_tuple: Enum::Tuple("first", 42)
721            => "<Tuple>first</Tuple>\
722                <Tuple>42</Tuple>");
723
724        // Structured types cannot be serialized without surrounding tag, which
725        // only `enum` can provide
726        err!(map: BTreeMap::from([("_1", 2), ("_3", 4)])
727            => Unsupported("serialization of map types is not supported in `$value` field"));
728        serialize_as!(struct_: Struct { key: "answer", val: (42, 42) }
729            => "<Struct>\
730                    <key>answer</key>\
731                    <val>42</val>\
732                    <val>42</val>\
733                </Struct>");
734
735        serialize_as!(enum_struct: Enum::Struct { key: "answer", val: (42, 42) }
736            => "<Struct>\
737                    <key>answer</key>\
738                    <val>42</val>\
739                    <val>42</val>\
740                </Struct>");
741
742        /// Special field name `$text` should be serialized as a text content
743        mod text_field {
744            use super::*;
745            use pretty_assertions::assert_eq;
746
747            err!(map: BTreeMap::from([("$text", 2), ("_3", 4)])
748                => Unsupported("serialization of map types is not supported in `$value` field"));
749            serialize_as!(struct_:
750                Text {
751                    before: "answer",
752                    content: (42, 42),
753                    after: "answer",
754                }
755                => "<Text>\
756                        <before>answer</before>\
757                        42 42\
758                        <after>answer</after>\
759                    </Text>");
760            serialize_as!(enum_struct:
761                SpecialEnum::Text {
762                    before: "answer",
763                    content: (42, 42),
764                    after: "answer",
765                }
766                => "<Text>\
767                        <before>answer</before>\
768                        42 42\
769                        <after>answer</after>\
770                    </Text>");
771        }
772
773        /// `$text` field inside a struct variant of an enum
774        mod enum_with_text_field {
775            use super::*;
776            use pretty_assertions::assert_eq;
777
778            macro_rules! text {
779                ($name:ident: $data:expr => $expected:literal) => {
780                    serialize_as!($name:
781                        SpecialEnum::Text {
782                            before: "answer",
783                            content: $data,
784                            after: "answer",
785                        }
786                        => concat!(
787                            "<Text><before>answer</before>",
788                            $expected,
789                            "<after>answer</after></Text>",
790                        ));
791                };
792            }
793
794            text!(false_: false => "false");
795            text!(true_:  true  => "true");
796
797            text!(i8_:    -42i8                => "-42");
798            text!(i16_:   -4200i16             => "-4200");
799            text!(i32_:   -42000000i32         => "-42000000");
800            text!(i64_:   -42000000000000i64   => "-42000000000000");
801            text!(isize_: -42000000isize       => "-42000000");
802
803            text!(u8_:    42u8                => "42");
804            text!(u16_:   4200u16             => "4200");
805            text!(u32_:   42000000u32         => "42000000");
806            text!(u64_:   42000000000000u64   => "42000000000000");
807            text!(usize_: 42000000usize       => "42000000");
808
809            text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
810            text!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
811
812            text!(f32_: 4.2f32 => "4.2");
813            text!(f64_: 4.2f64 => "4.2");
814
815            text!(char_non_escaped: 'h' => "h");
816            text!(char_lt:   '<' => "&lt;");
817            text!(char_gt:   '>' => "&gt;");
818            text!(char_amp:  '&' => "&amp;");
819            text!(char_apos: '\'' => "&apos;");
820            text!(char_quot: '"' => "&quot;");
821            text!(char_space: ' ' => " ");
822
823            text!(str_non_escaped: "non-escaped string" => "non-escaped string");
824            text!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
825
826            err!(bytes:
827                SpecialEnum::Text {
828                    before: "answer",
829                    content: Bytes(b"<\"escaped & bytes'>"),
830                    after: "answer",
831                }
832                => Unsupported("`serialize_bytes` not supported yet"));
833
834            text!(option_none: Option::<&str>::None => "");
835            text!(option_some: Some("non-escaped string") => "non-escaped string");
836            text!(option_some_empty_str: Some("") => "");
837
838            text!(unit: () => "");
839            text!(unit_struct: Unit => "");
840            text!(unit_struct_escaped: UnitEscaped => "");
841
842            text!(enum_unit: Enum::Unit => "Unit");
843            text!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
844
845            text!(newtype: Newtype(42) => "42");
846            // We have no space where name of a variant can be stored
847            err!(enum_newtype:
848                SpecialEnum::Text {
849                    before: "answer",
850                    content: Enum::Newtype(42),
851                    after: "answer",
852                }
853                => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value"));
854
855            // Sequences are serialized separated by spaces, all spaces inside are escaped
856            text!(seq: vec![1, 2, 3] => "1 2 3");
857            text!(seq_empty: Vec::<usize>::new() => "");
858            text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
859                => "&lt;&quot;&amp;&apos;&gt; \
860                    with&#9;&#10;&#13;&#32;spaces \
861                    3");
862            text!(tuple_struct: Tuple("first", 42) => "first 42");
863            // We have no space where name of a variant can be stored
864            err!(enum_tuple:
865                SpecialEnum::Text {
866                    before: "answer",
867                    content: Enum::Tuple("first", 42),
868                    after: "answer",
869                }
870                => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value"));
871
872            // Complex types cannot be serialized in `$text` field
873            err!(map:
874                SpecialEnum::Text {
875                    before: "answer",
876                    content: BTreeMap::from([("_1", 2), ("_3", 4)]),
877                    after: "answer",
878                }
879                => Unsupported("cannot serialize map as text content value"));
880            err!(struct_:
881                SpecialEnum::Text {
882                    before: "answer",
883                    content: Struct { key: "answer", val: (42, 42) },
884                    after: "answer",
885                }
886                => Unsupported("cannot serialize struct `Struct` as text content value"));
887            err!(enum_struct:
888                SpecialEnum::Text {
889                    before: "answer",
890                    content: Enum::Struct { key: "answer", val: (42, 42) },
891                    after: "answer",
892                }
893                => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value"));
894        }
895
896        /// `$value` field inside a struct variant of an enum
897        mod enum_with_value_field {
898            use super::*;
899            use pretty_assertions::assert_eq;
900
901            macro_rules! value {
902                ($name:ident: $data:expr => $expected:literal) => {
903                    serialize_as!($name:
904                        SpecialEnum::Value {
905                            before: "answer",
906                            content: $data,
907                            after: "answer",
908                        }
909                        => concat!(
910                            "<Value><before>answer</before>",
911                            $expected,
912                            "<after>answer</after></Value>",
913                        ));
914                };
915            }
916
917            value!(false_: false => "false");
918            value!(true_:  true  => "true");
919
920            value!(i8_:    -42i8                => "-42");
921            value!(i16_:   -4200i16             => "-4200");
922            value!(i32_:   -42000000i32         => "-42000000");
923            value!(i64_:   -42000000000000i64   => "-42000000000000");
924            value!(isize_: -42000000isize       => "-42000000");
925
926            value!(u8_:    42u8                => "42");
927            value!(u16_:   4200u16             => "4200");
928            value!(u32_:   42000000u32         => "42000000");
929            value!(u64_:   42000000000000u64   => "42000000000000");
930            value!(usize_: 42000000usize       => "42000000");
931
932            value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
933            value!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
934
935            value!(f32_: 4.2f32 => "4.2");
936            value!(f64_: 4.2f64 => "4.2");
937
938            value!(char_non_escaped: 'h' => "h");
939            value!(char_lt:   '<' => "&lt;");
940            value!(char_gt:   '>' => "&gt;");
941            value!(char_amp:  '&' => "&amp;");
942            value!(char_apos: '\'' => "&apos;");
943            value!(char_quot: '"' => "&quot;");
944            value!(char_space: ' ' => " ");
945
946            value!(str_non_escaped: "non-escaped string" => "non-escaped string");
947            value!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
948
949            err!(bytes:
950                SpecialEnum::Value {
951                    before: "answer",
952                    content: Bytes(b"<\"escaped & bytes'>"),
953                    after: "answer",
954                }
955                => Unsupported("`serialize_bytes` not supported yet"));
956
957            value!(option_none: Option::<&str>::None => "");
958            value!(option_some: Some("non-escaped string") => "non-escaped string");
959            value!(option_some_empty_str: Some("") => "");
960
961            value!(unit: () => "");
962            value!(unit_struct: Unit => "");
963            value!(unit_struct_escaped: UnitEscaped => "");
964
965            value!(enum_unit: Enum::Unit => "<Unit/>");
966            err!(enum_unit_escaped:
967                SpecialEnum::Value {
968                    before: "answer",
969                    content: Enum::UnitEscaped,
970                    after: "answer",
971                }
972                => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
973
974            value!(newtype: Newtype(42) => "42");
975            value!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>");
976
977            // Note that sequences of primitives serialized without delimiters!
978            err!(seq:
979                SpecialEnum::Value {
980                    before: "answer",
981                    content: vec![1, 2, 3],
982                    after: "answer",
983                }
984                => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
985            value!(seq_empty: Vec::<usize>::new() => "");
986            err!(tuple:
987                SpecialEnum::Value {
988                    before: "answer",
989                    content: ("<\"&'>", "with\t\n\r spaces", 3usize),
990                    after: "answer",
991                }
992                => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
993            err!(tuple_struct:
994                SpecialEnum::Value {
995                    before: "answer",
996                    content: Tuple("first", 42),
997                    after: "answer",
998                }
999                => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
1000            value!(enum_tuple: Enum::Tuple("first", 42)
1001                => "<Tuple>first</Tuple>\
1002                    <Tuple>42</Tuple>");
1003
1004            // We cannot wrap map or struct in any container and should not
1005            // flatten it, so it is impossible to serialize maps and structs
1006            err!(map:
1007                SpecialEnum::Value {
1008                    before: "answer",
1009                    content: BTreeMap::from([("_1", 2), ("_3", 4)]),
1010                    after: "answer",
1011                }
1012                => Unsupported("serialization of map types is not supported in `$value` field"));
1013            value!(struct_:
1014                SpecialEnum::Value {
1015                    before: "answer",
1016                    content: Struct { key: "answer", val: (42, 42) },
1017                    after: "answer",
1018                }
1019                => "<Value>\
1020                        <before>answer</before>\
1021                        <Struct>\
1022                            <key>answer</key>\
1023                            <val>42</val>\
1024                            <val>42</val>\
1025                        </Struct>\
1026                        <after>answer</after>\
1027                    </Value>");
1028            value!(enum_struct:
1029                Enum::Struct { key: "answer", val: (42, 42) }
1030                => "<Struct>\
1031                        <key>answer</key>\
1032                        <val>42</val>\
1033                        <val>42</val>\
1034                    </Struct>");
1035        }
1036
1037        mod attributes {
1038            use super::*;
1039            use pretty_assertions::assert_eq;
1040
1041            err!(map_attr: BTreeMap::from([("@key1", 1), ("@key2", 2)])
1042                => Unsupported("serialization of map types is not supported in `$value` field"));
1043            err!(map_mixed: BTreeMap::from([("@key1", 1), ("key2", 2)])
1044                => Unsupported("serialization of map types is not supported in `$value` field"));
1045
1046            serialize_as!(struct_: Attributes { key: "answer", val: (42, 42) }
1047                => r#"<Attributes key="answer" val="42 42"/>"#);
1048            serialize_as!(struct_before: AttributesBefore { key: "answer", val: 42 }
1049                => r#"<AttributesBefore key="answer"><val>42</val></AttributesBefore>"#);
1050            serialize_as!(struct_after: AttributesAfter { key: "answer", val: 42 }
1051                => r#"<AttributesAfter val="42"><key>answer</key></AttributesAfter>"#);
1052
1053            serialize_as!(enum_: Enum::Attributes { key: "answer", val: (42, 42) }
1054                => r#"<Attributes key="answer" val="42 42"/>"#);
1055            serialize_as!(enum_before: Enum::AttributesBefore { key: "answer", val: 42 }
1056                => r#"<AttributesBefore key="answer"><val>42</val></AttributesBefore>"#);
1057            serialize_as!(enum_after: Enum::AttributesAfter { key: "answer", val: 42 }
1058                => r#"<AttributesAfter val="42"><key>answer</key></AttributesAfter>"#);
1059        }
1060    }
1061
1062    mod with_indent {
1063        use super::Struct;
1064        use super::*;
1065        use crate::writer::Indentation;
1066        use pretty_assertions::assert_eq;
1067
1068        /// Checks that given `$data` successfully serialized as `$expected`
1069        macro_rules! serialize_as {
1070            ($name:ident: $data:expr => $expected:expr) => {
1071                serialize_as!($name: $data => $expected, WriteResult::Element);
1072            };
1073            ($name:ident: $data:expr => $expected:expr, $result:expr) => {
1074                #[test]
1075                fn $name() {
1076                    let mut buffer = String::new();
1077                    let ser = ContentSerializer {
1078                        writer: &mut buffer,
1079                        level: QuoteLevel::Full,
1080                        indent: Indent::Owned(Indentation::new(b' ', 2)),
1081                        write_indent: false,
1082                        text_format: TextFormat::Text,
1083                        allow_primitive: true,
1084                        empty_element_handling: EmptyElementHandling::SelfClosed,
1085                    };
1086
1087                    let result = $data.serialize(ser).unwrap();
1088                    assert_eq!(buffer, $expected);
1089                    assert_eq!(result, $result);
1090                }
1091            };
1092        }
1093
1094        /// Checks that attempt to serialize given `$data` results to a
1095        /// serialization error `$kind` with `$reason`
1096        macro_rules! err {
1097            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
1098                #[test]
1099                fn $name() {
1100                    let mut buffer = String::new();
1101                    let ser = ContentSerializer {
1102                        writer: &mut buffer,
1103                        level: QuoteLevel::Full,
1104                        indent: Indent::Owned(Indentation::new(b' ', 2)),
1105                        write_indent: false,
1106                        text_format: TextFormat::Text,
1107                        allow_primitive: true,
1108                        empty_element_handling: EmptyElementHandling::SelfClosed,
1109                    };
1110
1111                    match $data.serialize(ser).unwrap_err() {
1112                        SeError::$kind(e) => assert_eq!(e, $reason),
1113                        e => panic!(
1114                            "Expected `Err({}({}))`, but got `{:?}`",
1115                            stringify!($kind),
1116                            $reason,
1117                            e
1118                        ),
1119                    }
1120                    // We can write something before fail
1121                    // assert_eq!(buffer, "");
1122                }
1123            };
1124        }
1125
1126        serialize_as!(false_: false => "false", Text);
1127        serialize_as!(true_:  true  => "true", Text);
1128
1129        serialize_as!(i8_:    -42i8                => "-42", Text);
1130        serialize_as!(i16_:   -4200i16             => "-4200", Text);
1131        serialize_as!(i32_:   -42000000i32         => "-42000000", Text);
1132        serialize_as!(i64_:   -42000000000000i64   => "-42000000000000", Text);
1133        serialize_as!(isize_: -42000000isize       => "-42000000", Text);
1134
1135        serialize_as!(u8_:    42u8                => "42", Text);
1136        serialize_as!(u16_:   4200u16             => "4200", Text);
1137        serialize_as!(u32_:   42000000u32         => "42000000", Text);
1138        serialize_as!(u64_:   42000000000000u64   => "42000000000000", Text);
1139        serialize_as!(usize_: 42000000usize       => "42000000", Text);
1140
1141        serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000", Text);
1142        serialize_as!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000", Text);
1143
1144        serialize_as!(f32_: 4.2f32 => "4.2", Text);
1145        serialize_as!(f64_: 4.2f64 => "4.2", Text);
1146
1147        serialize_as!(char_non_escaped: 'h' => "h", SensitiveText);
1148        serialize_as!(char_lt:   '<' => "&lt;", SensitiveText);
1149        serialize_as!(char_gt:   '>' => "&gt;", SensitiveText);
1150        serialize_as!(char_amp:  '&' => "&amp;", SensitiveText);
1151        serialize_as!(char_apos: '\'' => "&apos;", SensitiveText);
1152        serialize_as!(char_quot: '"' => "&quot;", SensitiveText);
1153        serialize_as!(char_space: ' ' => " ", SensitiveText);
1154
1155        serialize_as!(str_non_escaped: "non-escaped string" => "non-escaped string", SensitiveText);
1156        serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;", SensitiveText);
1157
1158        err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("`serialize_bytes` not supported yet"));
1159
1160        serialize_as!(option_none: Option::<Enum>::None => "", SensitiveNothing);
1161        serialize_as!(option_some: Some(Enum::Unit) => "<Unit/>");
1162
1163        serialize_as!(unit: () => "", Nothing);
1164        serialize_as!(unit_struct: Unit => "", Nothing);
1165        serialize_as!(unit_struct_escaped: UnitEscaped => "", Nothing);
1166
1167        // Unlike SimpleTypeSerializer, enumeration values serialized as tags
1168        serialize_as!(enum_unit: Enum::Unit => "<Unit/>");
1169        err!(enum_unit_escaped: Enum::UnitEscaped
1170            => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
1171
1172        // Newtypes recursively applies ContentSerializer
1173        serialize_as!(newtype: Newtype(42) => "42", Text);
1174        serialize_as!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>");
1175
1176        err!(seq: vec![1, 2, 3]
1177            => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
1178        serialize_as!(seq_empty: Vec::<usize>::new() => "", SensitiveNothing);
1179        err!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
1180            => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
1181        err!(tuple_struct: Tuple("first", 42)
1182            => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
1183        serialize_as!(enum_tuple: Enum::Tuple("first", 42)
1184            => "<Tuple>first</Tuple>\n\
1185                <Tuple>42</Tuple>");
1186
1187        // Structured types cannot be serialized without surrounding tag, which
1188        // only `enum` can provide
1189        err!(map: BTreeMap::from([("_1", 2), ("_3", 4)])
1190            => Unsupported("serialization of map types is not supported in `$value` field"));
1191        serialize_as!(struct_: Struct { key: "answer", val: (42, 42) }
1192            => "<Struct>\n  \
1193                    <key>answer</key>\n  \
1194                    <val>42</val>\n  \
1195                    <val>42</val>\n\
1196                </Struct>");
1197        serialize_as!(enum_struct: Enum::Struct { key: "answer", val: (42, 42) }
1198            => "<Struct>\n  \
1199                    <key>answer</key>\n  \
1200                    <val>42</val>\n  \
1201                    <val>42</val>\n\
1202                </Struct>");
1203
1204        /// Special field name `$text` should be serialized as text content
1205        mod text_field {
1206            use super::*;
1207            use pretty_assertions::assert_eq;
1208
1209            err!(map: BTreeMap::from([("$text", 2), ("_3", 4)])
1210                => Unsupported("serialization of map types is not supported in `$value` field"));
1211            serialize_as!(struct_:
1212                Text {
1213                    before: "answer",
1214                    content: (42, 42),
1215                    after: "answer",
1216                }
1217                => "<Text>\n  \
1218                        <before>answer</before>42 42<after>answer</after>\n\
1219                    </Text>");
1220            serialize_as!(enum_struct:
1221                SpecialEnum::Text {
1222                    before: "answer",
1223                    content: (42, 42),
1224                    after: "answer",
1225                }
1226                => "<Text>\n  \
1227                        <before>answer</before>42 42<after>answer</after>\n\
1228                    </Text>");
1229        }
1230
1231        /// `$text` field inside a struct variant of an enum
1232        mod enum_with_text_field {
1233            use super::*;
1234            use pretty_assertions::assert_eq;
1235
1236            macro_rules! text {
1237                ($name:ident: $data:expr => $expected:literal) => {
1238                    serialize_as!($name:
1239                        SpecialEnum::Text {
1240                            before: "answer",
1241                            content: $data,
1242                            after: "answer",
1243                        }
1244                        => concat!(
1245                            "<Text>\n  <before>answer</before>",
1246                            $expected,
1247                            "<after>answer</after>\n</Text>",
1248                        ));
1249                };
1250            }
1251
1252            text!(false_: false => "false");
1253            text!(true_:  true  => "true");
1254
1255            text!(i8_:    -42i8                => "-42");
1256            text!(i16_:   -4200i16             => "-4200");
1257            text!(i32_:   -42000000i32         => "-42000000");
1258            text!(i64_:   -42000000000000i64   => "-42000000000000");
1259            text!(isize_: -42000000isize       => "-42000000");
1260
1261            text!(u8_:    42u8                => "42");
1262            text!(u16_:   4200u16             => "4200");
1263            text!(u32_:   42000000u32         => "42000000");
1264            text!(u64_:   42000000000000u64   => "42000000000000");
1265            text!(usize_: 42000000usize       => "42000000");
1266
1267            text!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1268            text!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1269
1270            text!(f32_: 4.2f32 => "4.2");
1271            text!(f64_: 4.2f64 => "4.2");
1272
1273            text!(char_non_escaped: 'h' => "h");
1274            text!(char_lt:   '<' => "&lt;");
1275            text!(char_gt:   '>' => "&gt;");
1276            text!(char_amp:  '&' => "&amp;");
1277            text!(char_apos: '\'' => "&apos;");
1278            text!(char_quot: '"' => "&quot;");
1279            text!(char_space: ' ' => " ");
1280
1281            text!(str_non_escaped: "non-escaped string" => "non-escaped string");
1282            text!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1283
1284            err!(bytes:
1285                SpecialEnum::Text {
1286                    before: "answer",
1287                    content: Bytes(b"<\"escaped & bytes'>"),
1288                    after: "answer",
1289                }
1290                => Unsupported("`serialize_bytes` not supported yet"));
1291
1292            text!(option_none: Option::<&str>::None => "");
1293            text!(option_some: Some("non-escaped string") => "non-escaped string");
1294            text!(option_some_empty_str: Some("") => "");
1295
1296            text!(unit: () => "");
1297            text!(unit_struct: Unit => "");
1298            text!(unit_struct_escaped: UnitEscaped => "");
1299
1300            text!(enum_unit: Enum::Unit => "Unit");
1301            text!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
1302
1303            text!(newtype: Newtype(42) => "42");
1304            // We have no space where name of a variant can be stored
1305            err!(enum_newtype:
1306                SpecialEnum::Text {
1307                    before: "answer",
1308                    content: Enum::Newtype(42),
1309                    after: "answer",
1310                }
1311                => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as text content value"));
1312
1313            // Sequences are serialized separated by spaces, all spaces inside are escaped
1314            text!(seq: vec![1, 2, 3] => "1 2 3");
1315            text!(seq_empty: Vec::<usize>::new() => "");
1316            text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1317                => "&lt;&quot;&amp;&apos;&gt; \
1318                    with&#9;&#10;&#13;&#32;spaces \
1319                    3");
1320            text!(tuple_struct: Tuple("first", 42) => "first 42");
1321            // We have no space where name of a variant can be stored
1322            err!(enum_tuple:
1323                SpecialEnum::Text {
1324                    before: "answer",
1325                    content: Enum::Tuple("first", 42),
1326                    after: "answer",
1327                }
1328                => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as text content value"));
1329
1330            // Complex types cannot be serialized in `$text` field
1331            err!(map:
1332                SpecialEnum::Text {
1333                    before: "answer",
1334                    content: BTreeMap::from([("_1", 2), ("_3", 4)]),
1335                    after: "answer",
1336                }
1337                => Unsupported("cannot serialize map as text content value"));
1338            err!(struct_:
1339                SpecialEnum::Text {
1340                    before: "answer",
1341                    content: Struct { key: "answer", val: (42, 42) },
1342                    after: "answer",
1343                }
1344                => Unsupported("cannot serialize struct `Struct` as text content value"));
1345            err!(enum_struct:
1346                SpecialEnum::Text {
1347                    before: "answer",
1348                    content: Enum::Struct { key: "answer", val: (42, 42) },
1349                    after: "answer",
1350                }
1351                => Unsupported("cannot serialize enum struct variant `Enum::Struct` as text content value"));
1352        }
1353
1354        /// `$value` field inside a struct variant of an enum
1355        mod enum_with_value_field {
1356            use super::*;
1357            use pretty_assertions::assert_eq;
1358
1359            macro_rules! value {
1360                ($name:ident: $data:expr => $expected:literal) => {
1361                    serialize_as!($name:
1362                        SpecialEnum::Value {
1363                            before: "answer",
1364                            content: $data,
1365                            after: "answer",
1366                        }
1367                        => concat!(
1368                            "<Value>\n  <before>answer</before>",
1369                            $expected,
1370                            "<after>answer</after>\n</Value>",
1371                        ));
1372                };
1373            }
1374
1375            value!(false_: false => "false");
1376            value!(true_:  true  => "true");
1377
1378            value!(i8_:    -42i8                => "-42");
1379            value!(i16_:   -4200i16             => "-4200");
1380            value!(i32_:   -42000000i32         => "-42000000");
1381            value!(i64_:   -42000000000000i64   => "-42000000000000");
1382            value!(isize_: -42000000isize       => "-42000000");
1383
1384            value!(u8_:    42u8                => "42");
1385            value!(u16_:   4200u16             => "4200");
1386            value!(u32_:   42000000u32         => "42000000");
1387            value!(u64_:   42000000000000u64   => "42000000000000");
1388            value!(usize_: 42000000usize => "42000000");
1389
1390            value!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1391            value!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1392
1393            value!(f32_: 4.2f32 => "4.2");
1394            value!(f64_: 4.2f64 => "4.2");
1395
1396            value!(char_non_escaped: 'h' => "h");
1397            value!(char_lt:   '<' => "&lt;");
1398            value!(char_gt:   '>' => "&gt;");
1399            value!(char_amp:  '&' => "&amp;");
1400            value!(char_apos: '\'' => "&apos;");
1401            value!(char_quot: '"' => "&quot;");
1402            value!(char_space: ' ' => " ");
1403
1404            value!(str_non_escaped: "non-escaped string" => "non-escaped string");
1405            value!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1406
1407            err!(bytes:
1408                SpecialEnum::Value {
1409                    before: "answer",
1410                    content: Bytes(b"<\"escaped & bytes'>"),
1411                    after: "answer",
1412                }
1413                => Unsupported("`serialize_bytes` not supported yet"));
1414
1415            value!(option_none: Option::<&str>::None => "");
1416            value!(option_some: Some("non-escaped string") => "non-escaped string");
1417            value!(option_some_empty_str: Some("") => "");
1418
1419            value!(unit: () => "\n  ");
1420            value!(unit_struct: Unit => "\n  ");
1421            value!(unit_struct_escaped: UnitEscaped => "\n  ");
1422
1423            value!(enum_unit: Enum::Unit => "\n  <Unit/>\n  ");
1424            err!(enum_unit_escaped:
1425                SpecialEnum::Value {
1426                    before: "answer",
1427                    content: Enum::UnitEscaped,
1428                    after: "answer",
1429                }
1430                => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
1431
1432            value!(newtype: Newtype(42) => "42");
1433            value!(enum_newtype: Enum::Newtype(42) => "\n  <Newtype>42</Newtype>\n  ");
1434
1435            // Note that sequences of primitives serialized without delimiters!
1436            err!(seq:
1437                SpecialEnum::Value {
1438                    before: "answer",
1439                    content: vec![1, 2, 3],
1440                    after: "answer",
1441                }
1442                => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
1443            value!(seq_empty: Vec::<usize>::new() => "");
1444            err!(tuple:
1445                SpecialEnum::Value {
1446                    before: "answer",
1447                    content: ("<\"&'>", "with\t\n\r spaces", 3usize),
1448                    after: "answer",
1449                }
1450                => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
1451            err!(tuple_struct:
1452                SpecialEnum::Value {
1453                    before: "answer",
1454                    content: Tuple("first", 42),
1455                    after: "answer",
1456                }
1457                => Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back"));
1458            value!(enum_tuple: Enum::Tuple("first", 42)
1459                => "\n  \
1460                    <Tuple>first</Tuple>\n  \
1461                    <Tuple>42</Tuple>\n  ");
1462
1463            // We cannot wrap map or struct in any container and should not
1464            // flatten it, so it is impossible to serialize maps and structs
1465            err!(map:
1466                SpecialEnum::Value {
1467                    before: "answer",
1468                    content: BTreeMap::from([("_1", 2), ("_3", 4)]),
1469                    after: "answer",
1470                }
1471                => Unsupported("serialization of map types is not supported in `$value` field"));
1472            value!(struct_:
1473                SpecialEnum::Value {
1474                    before: "answer",
1475                    content: Struct { key: "answer", val: (42, 42) },
1476                    after: "answer",
1477                }
1478                => "\n  \
1479                    <Value>\n    \
1480                        <before>answer</before>\n    \
1481                        <Struct>\n      \
1482                            <key>answer</key>\n      \
1483                            <val>42</val>\n      \
1484                            <val>42</val>\n    \
1485                        </Struct>\n    \
1486                        <after>answer</after>\n  \
1487                    </Value>\n  ");
1488            value!(enum_struct:
1489                Enum::Struct { key: "answer", val: (42, 42) }
1490                => "\n  \
1491                    <Struct>\n    \
1492                        <key>answer</key>\n    \
1493                        <val>42</val>\n    \
1494                        <val>42</val>\n  \
1495                    </Struct>\n  ");
1496        }
1497
1498        mod attributes {
1499            use super::*;
1500            use pretty_assertions::assert_eq;
1501
1502            err!(map_attr: BTreeMap::from([("@key1", 1), ("@key2", 2)])
1503                => Unsupported("serialization of map types is not supported in `$value` field"));
1504            err!(map_mixed: BTreeMap::from([("@key1", 1), ("key2", 2)])
1505                => Unsupported("serialization of map types is not supported in `$value` field"));
1506
1507            serialize_as!(struct_: Attributes { key: "answer", val: (42, 42) }
1508                => r#"<Attributes key="answer" val="42 42"/>"#);
1509            serialize_as!(struct_before: AttributesBefore { key: "answer", val: 42 }
1510                => "<AttributesBefore key=\"answer\">\n  \
1511                        <val>42</val>\n\
1512                    </AttributesBefore>");
1513            serialize_as!(struct_after: AttributesAfter { key: "answer", val: 42 }
1514                => "<AttributesAfter val=\"42\">\n  \
1515                        <key>answer</key>\n\
1516                    </AttributesAfter>");
1517
1518            serialize_as!(enum_: Enum::Attributes { key: "answer", val: (42, 42) }
1519                => r#"<Attributes key="answer" val="42 42"/>"#);
1520            serialize_as!(enum_before: Enum::AttributesBefore { key: "answer", val: 42 }
1521                => "<AttributesBefore key=\"answer\">\n  \
1522                        <val>42</val>\n\
1523                    </AttributesBefore>");
1524            serialize_as!(enum_after: Enum::AttributesAfter { key: "answer", val: 42 }
1525                => "<AttributesAfter val=\"42\">\n  \
1526                        <key>answer</key>\n\
1527                    </AttributesAfter>");
1528        }
1529    }
1530}