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