Coverage Report

Created: 2026-06-14 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/quick-xml-0.40.1/src/se/content.rs
Line
Count
Source
1
//! Contains serializer for content of an XML element
2
3
use crate::de::TEXT_KEY;
4
use crate::se::element::{ElementSerializer, Struct, Tuple};
5
use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
6
use crate::se::{
7
    EmptyElementHandling, Indent, QuoteLevel, SeError, TextFormat, WriteResult, XmlName,
8
};
9
use serde::ser::{
10
    Impossible, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct, Serializer,
11
};
12
use std::fmt::Write;
13
14
macro_rules! write_primitive {
15
    ($method:ident ( $ty:ty )) => {
16
        #[inline]
17
0
        fn $method(self, value: $ty) -> Result<Self::Ok, Self::Error> {
18
0
            self.into_simple_type_serializer()?.$method(value)?;
19
0
            Ok(WriteResult::Text)
20
0
        }
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_i8
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_u8
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_f32
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_f64
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_i16
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_i32
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_i64
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_u16
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_u32
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_u64
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_bool
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_i128
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_u128
Unexecuted instantiation: <quick_xml::se::content::ContentSerializer<_> as serde_core::ser::Serializer>::serialize_bytes
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.
63
pub 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
89
impl<'w, 'i, W: Write> ContentSerializer<'w, 'i, W> {
90
    /// Turns this serializer into serializer of a text content
91
    #[inline]
92
0
    pub fn into_simple_type_serializer_impl(self) -> SimpleTypeSerializer<&'w mut W> {
93
        SimpleTypeSerializer {
94
0
            writer: self.writer,
95
0
            target: match self.text_format {
96
0
                TextFormat::Text => QuoteTarget::Text,
97
0
                TextFormat::CData => QuoteTarget::CData,
98
            },
99
0
            level: self.level,
100
        }
101
0
    }
102
103
    /// Turns this serializer into serializer of a text content if that is allowed,
104
    /// otherwise error is returned
105
    #[inline]
106
0
    pub fn into_simple_type_serializer(self) -> Result<SimpleTypeSerializer<&'w mut W>, SeError> {
107
0
        if self.allow_primitive {
108
0
            Ok(self.into_simple_type_serializer_impl())
109
        } else {
110
0
            Err(SeError::Unsupported("consequent primitives would be serialized without delimiter and cannot be deserialized back".into()))
111
        }
112
0
    }
113
114
    /// Creates new serializer that shares state with this serializer and
115
    /// writes to the same underlying writer
116
    #[inline]
117
0
    pub fn new_seq_element_serializer(
118
0
        &mut self,
119
0
        allow_primitive: bool,
120
0
    ) -> ContentSerializer<'_, '_, W> {
121
0
        ContentSerializer {
122
0
            writer: self.writer,
123
0
            level: self.level,
124
0
            indent: self.indent.borrow(),
125
0
            write_indent: self.write_indent,
126
0
            text_format: self.text_format,
127
0
            allow_primitive,
128
0
            empty_element_handling: self.empty_element_handling,
129
0
        }
130
0
    }
131
132
    /// Writes `name` as self-closed tag
133
    #[inline]
134
0
    pub(super) fn write_empty(mut self, name: XmlName) -> Result<WriteResult, SeError> {
135
0
        self.write_indent()?;
136
137
0
        match self.empty_element_handling {
138
            EmptyElementHandling::SelfClosed => {
139
0
                self.writer.write_char('<')?;
140
0
                self.writer.write_str(name.0)?;
141
0
                self.writer.write_str("/>")?;
142
            }
143
            EmptyElementHandling::SelfClosedWithSpace => {
144
0
                self.writer.write_char('<')?;
145
0
                self.writer.write_str(name.0)?;
146
0
                self.writer.write_str(" />")?;
147
            }
148
            EmptyElementHandling::Expanded => {
149
0
                self.writer.write_char('<')?;
150
0
                self.writer.write_str(name.0)?;
151
0
                self.writer.write_str("></")?;
152
0
                self.writer.write_str(name.0)?;
153
0
                self.writer.write_char('>')?;
154
            }
155
        }
156
157
0
        Ok(WriteResult::Element)
158
0
    }
159
160
    /// Writes simple type content between `name` tags
161
0
    pub(super) fn write_wrapped<S>(
162
0
        mut self,
163
0
        name: XmlName,
164
0
        serialize: S,
165
0
    ) -> Result<WriteResult, SeError>
166
0
    where
167
0
        S: for<'a> FnOnce(SimpleTypeSerializer<&'a mut W>) -> Result<&'a mut W, SeError>,
168
    {
169
0
        self.write_indent()?;
170
0
        self.writer.write_char('<')?;
171
0
        self.writer.write_str(name.0)?;
172
0
        self.writer.write_char('>')?;
173
174
0
        let writer = serialize(self.into_simple_type_serializer_impl())?;
175
176
0
        writer.write_str("</")?;
177
0
        writer.write_str(name.0)?;
178
0
        writer.write_char('>')?;
179
0
        Ok(WriteResult::Element)
180
0
    }
181
182
0
    pub(super) fn write_indent(&mut self) -> Result<(), SeError> {
183
0
        if self.write_indent {
184
0
            self.indent.write_indent(&mut self.writer)?;
185
0
            self.write_indent = false;
186
0
        }
187
0
        Ok(())
188
0
    }
189
}
190
191
impl<'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
0
    fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
225
0
        self.into_simple_type_serializer()?.serialize_char(value)?;
226
0
        Ok(WriteResult::SensitiveText)
227
0
    }
228
229
    #[inline]
230
0
    fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
231
0
        if !value.is_empty() {
232
0
            self.into_simple_type_serializer()?.serialize_str(value)?;
233
0
        }
234
0
        Ok(WriteResult::SensitiveText)
235
0
    }
236
237
    /// Does not write anything
238
    #[inline]
239
0
    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
0
        Ok(WriteResult::SensitiveNothing)
244
0
    }
245
246
0
    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
247
0
        value.serialize(self)
248
0
    }
249
250
    /// Does not write anything
251
    #[inline]
252
0
    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
253
0
        Ok(WriteResult::Nothing)
254
0
    }
255
256
    /// Does not write anything
257
    #[inline]
258
0
    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
259
0
        Ok(WriteResult::Nothing)
260
0
    }
261
262
    /// If `variant` is a special `$text` variant, then do nothing, otherwise
263
    /// checks `variant` for XML name validity and writes `<variant/>`.
264
0
    fn serialize_unit_variant(
265
0
        self,
266
0
        _name: &'static str,
267
0
        _variant_index: u32,
268
0
        variant: &'static str,
269
0
    ) -> Result<Self::Ok, Self::Error> {
270
0
        if variant == TEXT_KEY {
271
0
            Ok(WriteResult::Nothing)
272
        } else {
273
0
            let name = XmlName::try_from(variant)?;
274
0
            self.write_empty(name)
275
        }
276
0
    }
277
278
0
    fn serialize_newtype_struct<T: ?Sized + Serialize>(
279
0
        self,
280
0
        _name: &'static str,
281
0
        value: &T,
282
0
    ) -> Result<Self::Ok, Self::Error> {
283
0
        value.serialize(self)
284
0
    }
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
0
    fn serialize_newtype_variant<T: ?Sized + Serialize>(
290
0
        self,
291
0
        _name: &'static str,
292
0
        _variant_index: u32,
293
0
        variant: &'static str,
294
0
        value: &T,
295
0
    ) -> Result<Self::Ok, Self::Error> {
296
0
        if variant == TEXT_KEY {
297
0
            value.serialize(self.into_simple_type_serializer()?)?;
298
0
            Ok(WriteResult::SensitiveText)
299
        } else {
300
0
            value.serialize(ElementSerializer {
301
0
                key: XmlName::try_from(variant)?,
302
0
                ser: self,
303
0
            })?;
304
0
            Ok(WriteResult::Element)
305
        }
306
0
    }
307
308
    #[inline]
309
0
    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
310
0
        Ok(Seq {
311
0
            ser: self,
312
0
            // If sequence if empty, nothing will be serialized. Because sequence can be of `Option`s
313
0
            // we need to assume that writing indent may change the data and do not write anything
314
0
            last: WriteResult::SensitiveNothing,
315
0
        })
316
0
    }
317
318
    #[inline]
319
0
    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
320
0
        self.serialize_seq(Some(len))
321
0
    }
322
323
    #[inline]
324
0
    fn serialize_tuple_struct(
325
0
        self,
326
0
        _name: &'static str,
327
0
        len: usize,
328
0
    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
329
0
        self.serialize_tuple(len)
330
0
    }
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
0
    fn serialize_tuple_variant(
342
0
        self,
343
0
        name: &'static str,
344
0
        _variant_index: u32,
345
0
        variant: &'static str,
346
0
        len: usize,
347
0
    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
348
0
        if variant == TEXT_KEY {
349
0
            self.into_simple_type_serializer()?
350
0
                .serialize_tuple_struct(name, len)
351
0
                .map(Tuple::Text)
352
        } else {
353
0
            let ser = ElementSerializer {
354
0
                key: XmlName::try_from(variant)?,
355
0
                ser: self,
356
            };
357
0
            ser.serialize_tuple_struct(name, len).map(Tuple::Element)
358
        }
359
0
    }
360
361
0
    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
362
0
        Err(SeError::Unsupported(
363
0
            "serialization of map types is not supported in `$value` field".into(),
364
0
        ))
365
0
    }
366
367
    #[inline]
368
0
    fn serialize_struct(
369
0
        self,
370
0
        name: &'static str,
371
0
        len: usize,
372
0
    ) -> Result<Self::SerializeStruct, Self::Error> {
373
        ElementSerializer {
374
0
            ser: self,
375
0
            key: XmlName::try_from(name)?,
376
        }
377
0
        .serialize_struct(name, len)
378
0
    }
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
0
    fn serialize_struct_variant(
392
0
        self,
393
0
        name: &'static str,
394
0
        _variant_index: u32,
395
0
        variant: &'static str,
396
0
        len: usize,
397
0
    ) -> Result<Self::SerializeStructVariant, Self::Error> {
398
0
        if variant == TEXT_KEY {
399
0
            Err(SeError::Unsupported(
400
0
                format!("cannot serialize `$text` struct variant of `{}` enum", name).into(),
401
0
            ))
402
        } else {
403
0
            let ser = ElementSerializer {
404
0
                key: XmlName::try_from(variant)?,
405
0
                ser: self,
406
            };
407
0
            ser.serialize_struct(name, len)
408
        }
409
0
    }
410
}
411
412
////////////////////////////////////////////////////////////////////////////////////////////////////
413
414
/// Helper struct which remembers the classification of the last serialized element
415
/// and reports it when the sequence ends
416
pub 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
422
impl<'w, 'i, W: Write> SerializeSeq for Seq<'w, 'i, W> {
423
    type Ok = WriteResult;
424
    type Error = SeError;
425
426
0
    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
427
0
    where
428
0
        T: ?Sized + Serialize,
429
    {
430
0
        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
0
        self.ser.write_indent = self.last.allow_indent();
433
0
        Ok(())
434
0
    }
435
436
    #[inline]
437
0
    fn end(self) -> Result<Self::Ok, Self::Error> {
438
0
        Ok(self.last)
439
0
    }
440
}
441
442
impl<'w, 'i, W: Write> SerializeTuple for Seq<'w, 'i, W> {
443
    type Ok = WriteResult;
444
    type Error = SeError;
445
446
    #[inline]
447
0
    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
448
0
    where
449
0
        T: ?Sized + Serialize,
450
    {
451
0
        SerializeSeq::serialize_element(self, value)
452
0
    }
453
454
    #[inline]
455
0
    fn end(self) -> Result<Self::Ok, Self::Error> {
456
0
        SerializeSeq::end(self)
457
0
    }
458
}
459
460
impl<'w, 'i, W: Write> SerializeTupleStruct for Seq<'w, 'i, W> {
461
    type Ok = WriteResult;
462
    type Error = SeError;
463
464
    #[inline]
465
0
    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
466
0
    where
467
0
        T: ?Sized + Serialize,
468
    {
469
0
        SerializeSeq::serialize_element(self, value)
470
0
    }
471
472
    #[inline]
473
0
    fn end(self) -> Result<Self::Ok, Self::Error> {
474
0
        SerializeSeq::end(self)
475
0
    }
476
}
477
478
////////////////////////////////////////////////////////////////////////////////////////////////////
479
480
/// Make tests public to reuse types in `elements::tests` module
481
#[cfg(test)]
482
pub(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
}