Coverage Report

Created: 2026-01-15 06:51

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