1//! Contains serializer for content of an XML element
2
3use crate::errors::serialize::DeError;
4use crate::se::element::{ElementSerializer, Struct, Tuple};
5use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
6use crate::se::{Indent, QuoteLevel, XmlName};
7use serde::ser::{
8 Impossible, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct, Serializer,
9};
10use serde::serde_if_integer128;
11use std::fmt::Write;
12
13macro_rules! write_primitive {
14 ($method:ident ( $ty:ty )) => {
15 #[inline]
16 fn $method(self, value: $ty) -> Result<Self::Ok, Self::Error> {
17 self.into_simple_type_serializer().$method(value)?;
18 Ok(())
19 }
20 };
21}
22
23////////////////////////////////////////////////////////////////////////////////////////////////////
24
25/// A serializer used to serialize content of the element. It does not write
26/// surrounding tags.
27///
28/// This serializer does the following:
29/// - primitives (booleans, numbers and strings) serialized as naked strings
30/// - `None` does not write anything
31/// - sequences serialized without delimiters. `[1, 2, 3]` would be serialized as `123`
32/// - units (`()`) and unit structs are not supported
33/// - structs and maps are not supported
34/// - unit variants serialized as self-closed `<${variant}/>`
35/// - tuple variants serialized as sequences where each is wrapped in
36/// `<${variant}>...</${variant}>`
37/// - struct variants serialized wrapped `<${variant}>...</${variant}>`
38///
39/// The difference between this serializer and [`SimpleTypeSerializer`] is in how
40/// sequences and maps are serialized. Unlike `SimpleTypeSerializer` it supports
41/// any types in sequences and serializes them as list of elements, but that has
42/// drawbacks. Sequence of primitives would be serialized without delimiters and
43/// it will be impossible to distinguish between them. Even worse, when serializing
44/// with indent, sequence of strings become one big string with additional content
45/// and it would be impossible to distinguish between content of the original
46/// strings and inserted indent characters.
47pub struct ContentSerializer<'w, 'i, W: Write> {
48 pub writer: &'w mut W,
49 /// Defines which XML characters need to be escaped in text content
50 pub level: QuoteLevel,
51 /// Current indentation level. Note, that `Indent::None` means that there is
52 /// no indentation at all, but `write_indent == false` means only, that indent
53 /// writing is disabled in this instantiation of `ContentSerializer`, but
54 /// child serializers should have access to the actual state of indentation.
55 pub(super) indent: Indent<'i>,
56 /// If `true`, then current indent will be written before writing the content,
57 /// but only if content is not empty.
58 pub write_indent: bool,
59 // If `true`, then empty elements will be serialized as `<element></element>`
60 // instead of `<element/>`.
61 pub expand_empty_elements: bool,
62 //TODO: add settings to disallow consequent serialization of primitives
63}
64
65impl<'w, 'i, W: Write> ContentSerializer<'w, 'i, W> {
66 /// Turns this serializer into serializer of a text content
67 #[inline]
68 pub fn into_simple_type_serializer(self) -> SimpleTypeSerializer<'i, &'w mut W> {
69 //TODO: Customization point: choose between CDATA and Text representation
70 SimpleTypeSerializer {
71 writer: self.writer,
72 target: QuoteTarget::Text,
73 level: self.level,
74 indent: if self.write_indent {
75 self.indent
76 } else {
77 Indent::None
78 },
79 }
80 }
81
82 /// Creates new serializer that shares state with this serializer and
83 /// writes to the same underlying writer
84 #[inline]
85 pub fn new_seq_element_serializer(&mut self) -> ContentSerializer<W> {
86 ContentSerializer {
87 writer: self.writer,
88 level: self.level,
89 indent: self.indent.borrow(),
90 write_indent: self.write_indent,
91 expand_empty_elements: self.expand_empty_elements,
92 }
93 }
94
95 /// Writes `name` as self-closed tag
96 #[inline]
97 pub(super) fn write_empty(mut self, name: XmlName) -> Result<(), DeError> {
98 self.write_indent()?;
99 if self.expand_empty_elements {
100 self.writer.write_char('<')?;
101 self.writer.write_str(name.0)?;
102 self.writer.write_str("></")?;
103 self.writer.write_str(name.0)?;
104 self.writer.write_char('>')?;
105 } else {
106 self.writer.write_str("<")?;
107 self.writer.write_str(name.0)?;
108 self.writer.write_str("/>")?;
109 }
110 Ok(())
111 }
112
113 /// Writes simple type content between `name` tags
114 pub(super) fn write_wrapped<S>(mut self, name: XmlName, serialize: S) -> Result<(), DeError>
115 where
116 S: for<'a> FnOnce(SimpleTypeSerializer<'i, &'a mut W>) -> Result<&'a mut W, DeError>,
117 {
118 self.write_indent()?;
119 self.writer.write_char('<')?;
120 self.writer.write_str(name.0)?;
121 self.writer.write_char('>')?;
122
123 let writer = serialize(self.into_simple_type_serializer())?;
124
125 writer.write_str("</")?;
126 writer.write_str(name.0)?;
127 writer.write_char('>')?;
128 Ok(())
129 }
130
131 pub(super) fn write_indent(&mut self) -> Result<(), DeError> {
132 if self.write_indent {
133 self.indent.write_indent(&mut self.writer)?;
134 self.write_indent = false;
135 }
136 Ok(())
137 }
138}
139
140impl<'w, 'i, W: Write> Serializer for ContentSerializer<'w, 'i, W> {
141 type Ok = ();
142 type Error = DeError;
143
144 type SerializeSeq = Self;
145 type SerializeTuple = Self;
146 type SerializeTupleStruct = Self;
147 type SerializeTupleVariant = Tuple<'w, 'i, W>;
148 type SerializeMap = Impossible<Self::Ok, Self::Error>;
149 type SerializeStruct = Impossible<Self::Ok, Self::Error>;
150 type SerializeStructVariant = Struct<'w, 'i, W>;
151
152 write_primitive!(serialize_bool(bool));
153
154 write_primitive!(serialize_i8(i8));
155 write_primitive!(serialize_i16(i16));
156 write_primitive!(serialize_i32(i32));
157 write_primitive!(serialize_i64(i64));
158
159 write_primitive!(serialize_u8(u8));
160 write_primitive!(serialize_u16(u16));
161 write_primitive!(serialize_u32(u32));
162 write_primitive!(serialize_u64(u64));
163
164 serde_if_integer128! {
165 write_primitive!(serialize_i128(i128));
166 write_primitive!(serialize_u128(u128));
167 }
168
169 write_primitive!(serialize_f32(f32));
170 write_primitive!(serialize_f64(f64));
171
172 write_primitive!(serialize_char(char));
173 write_primitive!(serialize_bytes(&[u8]));
174
175 #[inline]
176 fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
177 if !value.is_empty() {
178 self.into_simple_type_serializer().serialize_str(value)?;
179 }
180 Ok(())
181 }
182
183 /// Does not write anything
184 #[inline]
185 fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
186 Ok(())
187 }
188
189 fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
190 value.serialize(self)
191 }
192
193 /// Does not write anything
194 #[inline]
195 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
196 Ok(())
197 }
198
199 /// Does not write anything
200 #[inline]
201 fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
202 Ok(())
203 }
204
205 /// Checks `variant` for XML name validity and writes `<${variant}/>`
206 fn serialize_unit_variant(
207 self,
208 _name: &'static str,
209 _variant_index: u32,
210 variant: &'static str,
211 ) -> Result<Self::Ok, Self::Error> {
212 let name = XmlName::try_from(variant)?;
213 self.write_empty(name)
214 }
215
216 fn serialize_newtype_struct<T: ?Sized + Serialize>(
217 self,
218 _name: &'static str,
219 value: &T,
220 ) -> Result<Self::Ok, Self::Error> {
221 value.serialize(self)
222 }
223
224 /// Checks `variant` for XML name validity and writes `value` as new element
225 /// with name `variant`.
226 fn serialize_newtype_variant<T: ?Sized + Serialize>(
227 self,
228 _name: &'static str,
229 _variant_index: u32,
230 variant: &'static str,
231 value: &T,
232 ) -> Result<Self::Ok, Self::Error> {
233 value.serialize(ElementSerializer {
234 key: XmlName::try_from(variant)?,
235 ser: self,
236 })
237 }
238
239 #[inline]
240 fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
241 Ok(self)
242 }
243
244 #[inline]
245 fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
246 self.serialize_seq(Some(len))
247 }
248
249 #[inline]
250 fn serialize_tuple_struct(
251 self,
252 _name: &'static str,
253 len: usize,
254 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
255 self.serialize_tuple(len)
256 }
257
258 #[inline]
259 fn serialize_tuple_variant(
260 self,
261 name: &'static str,
262 _variant_index: u32,
263 variant: &'static str,
264 len: usize,
265 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
266 let ser = ElementSerializer {
267 key: XmlName::try_from(variant)?,
268 ser: self,
269 };
270 // `ElementSerializer::serialize_tuple_variant` is the same as
271 // `ElementSerializer::serialize_tuple_struct`, except that it replaces `.key`
272 // to `variant` which is not required here
273 ser.serialize_tuple_struct(name, len).map(Tuple::Element)
274 }
275
276 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
277 Err(DeError::Unsupported(
278 format!("serialization of map types is not supported in `$value` field").into(),
279 ))
280 }
281
282 #[inline]
283 fn serialize_struct(
284 self,
285 name: &'static str,
286 _len: usize,
287 ) -> Result<Self::SerializeStruct, Self::Error> {
288 Err(DeError::Unsupported(
289 format!("serialization of struct `{name}` is not supported in `$value` field").into(),
290 ))
291 }
292
293 #[inline]
294 fn serialize_struct_variant(
295 self,
296 name: &'static str,
297 _variant_index: u32,
298 variant: &'static str,
299 len: usize,
300 ) -> Result<Self::SerializeStructVariant, Self::Error> {
301 let ser = ElementSerializer {
302 key: XmlName::try_from(variant)?,
303 ser: self,
304 };
305 // `ElementSerializer::serialize_struct_variant` is the same as
306 // `ElementSerializer::serialize_struct`, except that it replaces `.key`
307 // to `variant` which is not required here
308 ser.serialize_struct(name, len)
309 }
310}
311
312impl<'w, 'i, W: Write> SerializeSeq for ContentSerializer<'w, 'i, W> {
313 type Ok = ();
314 type Error = DeError;
315
316 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
317 where
318 T: ?Sized + Serialize,
319 {
320 value.serialize(self.new_seq_element_serializer())?;
321 // Write indent for next element
322 self.write_indent = true;
323 Ok(())
324 }
325
326 #[inline]
327 fn end(self) -> Result<Self::Ok, Self::Error> {
328 Ok(())
329 }
330}
331
332impl<'w, 'i, W: Write> SerializeTuple for ContentSerializer<'w, 'i, W> {
333 type Ok = ();
334 type Error = DeError;
335
336 #[inline]
337 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
338 where
339 T: ?Sized + Serialize,
340 {
341 <Self as SerializeSeq>::serialize_element(self, value)
342 }
343
344 #[inline]
345 fn end(self) -> Result<Self::Ok, Self::Error> {
346 <Self as SerializeSeq>::end(self)
347 }
348}
349
350impl<'w, 'i, W: Write> SerializeTupleStruct for ContentSerializer<'w, 'i, W> {
351 type Ok = ();
352 type Error = DeError;
353
354 #[inline]
355 fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
356 where
357 T: ?Sized + Serialize,
358 {
359 <Self as SerializeSeq>::serialize_element(self, value)
360 }
361
362 #[inline]
363 fn end(self) -> Result<Self::Ok, Self::Error> {
364 <Self as SerializeSeq>::end(self)
365 }
366}
367
368////////////////////////////////////////////////////////////////////////////////////////////////////
369
370/// Make tests public to reuse types in `elements::tests` module
371#[cfg(test)]
372pub(super) mod tests {
373 use super::*;
374 use crate::utils::Bytes;
375 use serde::Serialize;
376 use std::collections::BTreeMap;
377
378 #[derive(Debug, Serialize, PartialEq)]
379 pub struct Unit;
380
381 #[derive(Debug, Serialize, PartialEq)]
382 #[serde(rename = "<\"&'>")]
383 pub struct UnitEscaped;
384
385 #[derive(Debug, Serialize, PartialEq)]
386 pub struct Newtype(pub usize);
387
388 #[derive(Debug, Serialize, PartialEq)]
389 pub struct Tuple(pub &'static str, pub usize);
390
391 #[derive(Debug, Serialize, PartialEq)]
392 pub struct Struct {
393 pub key: &'static str,
394 pub val: (usize, usize),
395 }
396
397 #[derive(Debug, Serialize, PartialEq)]
398 pub struct Text<T> {
399 pub before: &'static str,
400 #[serde(rename = "$text")]
401 pub content: T,
402 pub after: &'static str,
403 }
404
405 #[derive(Debug, Serialize, PartialEq)]
406 pub struct Value<T> {
407 pub before: &'static str,
408 #[serde(rename = "$value")]
409 pub content: T,
410 pub after: &'static str,
411 }
412
413 /// Attributes identified by starting with `@` character
414 #[derive(Debug, Serialize, PartialEq)]
415 pub struct Attributes {
416 #[serde(rename = "@key")]
417 pub key: &'static str,
418 #[serde(rename = "@val")]
419 pub val: (usize, usize),
420 }
421 #[derive(Debug, Serialize, PartialEq)]
422 pub struct AttributesBefore {
423 #[serde(rename = "@key")]
424 pub key: &'static str,
425 pub val: usize,
426 }
427 #[derive(Debug, Serialize, PartialEq)]
428 pub struct AttributesAfter {
429 pub key: &'static str,
430 #[serde(rename = "@val")]
431 pub val: usize,
432 }
433
434 #[derive(Debug, Serialize, PartialEq)]
435 pub enum Enum {
436 Unit,
437 /// Variant name becomes a tag name, but the name of variant is invalid
438 /// XML name. Serialization of this element should be forbidden
439 #[serde(rename = "<\"&'>")]
440 UnitEscaped,
441 Newtype(usize),
442 Tuple(&'static str, usize),
443 Struct {
444 key: &'static str,
445 /// Should be serialized as elements
446 val: (usize, usize),
447 },
448 Attributes {
449 #[serde(rename = "@key")]
450 key: &'static str,
451 #[serde(rename = "@val")]
452 val: (usize, usize),
453 },
454 AttributesBefore {
455 #[serde(rename = "@key")]
456 key: &'static str,
457 val: usize,
458 },
459 AttributesAfter {
460 key: &'static str,
461 #[serde(rename = "@val")]
462 val: usize,
463 },
464 }
465
466 #[derive(Debug, Serialize, PartialEq)]
467 pub enum SpecialEnum<T> {
468 Text {
469 before: &'static str,
470 #[serde(rename = "$text")]
471 content: T,
472 after: &'static str,
473 },
474 Value {
475 before: &'static str,
476 #[serde(rename = "$value")]
477 content: T,
478 after: &'static str,
479 },
480 }
481
482 mod without_indent {
483 use super::Struct;
484 use super::*;
485 use pretty_assertions::assert_eq;
486
487 /// Checks that given `$data` successfully serialized as `$expected`
488 macro_rules! serialize_as {
489 ($name:ident: $data:expr => $expected:literal) => {
490 #[test]
491 fn $name() {
492 let mut buffer = String::new();
493 let ser = ContentSerializer {
494 writer: &mut buffer,
495 level: QuoteLevel::Full,
496 indent: Indent::None,
497 write_indent: false,
498 expand_empty_elements: false,
499 };
500
501 $data.serialize(ser).unwrap();
502 assert_eq!(buffer, $expected);
503 }
504 };
505 }
506
507 /// Checks that attempt to serialize given `$data` results to a
508 /// serialization error `$kind` with `$reason`
509 macro_rules! err {
510 ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
511 #[test]
512 fn $name() {
513 let mut buffer = String::new();
514 let ser = ContentSerializer {
515 writer: &mut buffer,
516 level: QuoteLevel::Full,
517 indent: Indent::None,
518 write_indent: false,
519 expand_empty_elements: false,
520 };
521
522 match $data.serialize(ser).unwrap_err() {
523 DeError::$kind(e) => assert_eq!(e, $reason),
524 e => panic!(
525 "Expected `{}({})`, found `{:?}`",
526 stringify!($kind),
527 $reason,
528 e
529 ),
530 }
531 // We could write something before fail
532 // assert_eq!(buffer, "");
533 }
534 };
535 }
536
537 // Primitives is serialized in the same way as for SimpleTypeSerializer
538 serialize_as!(false_: false => "false");
539 serialize_as!(true_: true => "true");
540
541 serialize_as!(i8_: -42i8 => "-42");
542 serialize_as!(i16_: -4200i16 => "-4200");
543 serialize_as!(i32_: -42000000i32 => "-42000000");
544 serialize_as!(i64_: -42000000000000i64 => "-42000000000000");
545 serialize_as!(isize_: -42000000000000isize => "-42000000000000");
546
547 serialize_as!(u8_: 42u8 => "42");
548 serialize_as!(u16_: 4200u16 => "4200");
549 serialize_as!(u32_: 42000000u32 => "42000000");
550 serialize_as!(u64_: 42000000000000u64 => "42000000000000");
551 serialize_as!(usize_: 42000000000000usize => "42000000000000");
552
553 serde_if_integer128! {
554 serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
555 serialize_as!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000");
556 }
557
558 serialize_as!(f32_: 4.2f32 => "4.2");
559 serialize_as!(f64_: 4.2f64 => "4.2");
560
561 serialize_as!(char_non_escaped: 'h' => "h");
562 serialize_as!(char_lt: '<' => "&lt;");
563 serialize_as!(char_gt: '>' => "&gt;");
564 serialize_as!(char_amp: '&' => "&amp;");
565 serialize_as!(char_apos: '\'' => "&apos;");
566 serialize_as!(char_quot: '"' => "&quot;");
567 //TODO: add a setting to escape leading/trailing spaces, in order to
568 // pretty-print does not change the content
569 serialize_as!(char_space: ' ' => " ");
570
571 serialize_as!(str_non_escaped: "non-escaped string" => "non-escaped string");
572 serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
573
574 err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("`serialize_bytes` not supported yet"));
575
576 serialize_as!(option_none: Option::<Enum>::None => "");
577 serialize_as!(option_some: Some("non-escaped string") => "non-escaped string");
578 serialize_as!(option_some_empty_str: Some("") => "");
579
580 serialize_as!(unit: () => "");
581 serialize_as!(unit_struct: Unit => "");
582 serialize_as!(unit_struct_escaped: UnitEscaped => "");
583
584 // Unlike SimpleTypeSerializer, enumeration values serialized as tags
585 serialize_as!(enum_unit: Enum::Unit => "<Unit/>");
586 err!(enum_unit_escaped: Enum::UnitEscaped
587 => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
588
589 // Newtypes recursively applies ContentSerializer
590 serialize_as!(newtype: Newtype(42) => "42");
591 serialize_as!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>");
592
593 // Note that sequences of primitives serialized without delimiters!
594 serialize_as!(seq: vec![1, 2, 3] => "123");
595 serialize_as!(seq_empty: Vec::<usize>::new() => "");
596 serialize_as!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
597 => "&lt;&quot;&amp;&apos;&gt;\
598 with\t\r\n spaces\
599 3");
600 serialize_as!(tuple_struct: Tuple("first", 42)
601 => "first\
602 42");
603 serialize_as!(enum_tuple: Enum::Tuple("first", 42)
604 => "<Tuple>first</Tuple>\
605 <Tuple>42</Tuple>");
606
607 // Structured types cannot be serialized without surrounding tag, which
608 // only `enum` can provide
609 err!(map: BTreeMap::from([("_1", 2), ("_3", 4)])
610 => Unsupported("serialization of map types is not supported in `$value` field"));
611 err!(struct_: Struct { key: "answer", val: (42, 42) }
612 => Unsupported("serialization of struct `Struct` is not supported in `$value` field"));
613 serialize_as!(enum_struct: Enum::Struct { key: "answer", val: (42, 42) }
614 => "<Struct>\
615 <key>answer</key>\
616 <val>42</val>\
617 <val>42</val>\
618 </Struct>");
619
620 /// Special field name `$text` should be serialized as a text content
621 mod text {
622 use super::*;
623 use pretty_assertions::assert_eq;
624
625 err!(map: BTreeMap::from([("$text", 2), ("_3", 4)])
626 => Unsupported("serialization of map types is not supported in `$value` field"));
627 err!(struct_:
628 Text {
629 before: "answer",
630 content: (42, 42),
631 after: "answer",
632 }
633 => Unsupported("serialization of struct `Text` is not supported in `$value` field"));
634 serialize_as!(enum_struct:
635 SpecialEnum::Text {
636 before: "answer",
637 content: (42, 42),
638 after: "answer",
639 }
640 => "<Text>\
641 <before>answer</before>\
642 42 42\
643 <after>answer</after>\
644 </Text>");
645 }
646
647 mod attributes {
648 use super::*;
649 use pretty_assertions::assert_eq;
650
651 err!(map_attr: BTreeMap::from([("@key1", 1), ("@key2", 2)])
652 => Unsupported("serialization of map types is not supported in `$value` field"));
653 err!(map_mixed: BTreeMap::from([("@key1", 1), ("key2", 2)])
654 => Unsupported("serialization of map types is not supported in `$value` field"));
655
656 err!(struct_: Attributes { key: "answer", val: (42, 42) }
657 => Unsupported("serialization of struct `Attributes` is not supported in `$value` field"));
658 err!(struct_before: AttributesBefore { key: "answer", val: 42 }
659 => Unsupported("serialization of struct `AttributesBefore` is not supported in `$value` field"));
660 err!(struct_after: AttributesAfter { key: "answer", val: 42 }
661 => Unsupported("serialization of struct `AttributesAfter` is not supported in `$value` field"));
662
663 serialize_as!(enum_: Enum::Attributes { key: "answer", val: (42, 42) }
664 => r#"<Attributes key="answer" val="42 42"/>"#);
665 serialize_as!(enum_before: Enum::AttributesBefore { key: "answer", val: 42 }
666 => r#"<AttributesBefore key="answer"><val>42</val></AttributesBefore>"#);
667 serialize_as!(enum_after: Enum::AttributesAfter { key: "answer", val: 42 }
668 => r#"<AttributesAfter val="42"><key>answer</key></AttributesAfter>"#);
669 }
670 }
671
672 mod with_indent {
673 use super::Struct;
674 use super::*;
675 use crate::writer::Indentation;
676 use pretty_assertions::assert_eq;
677
678 /// Checks that given `$data` successfully serialized as `$expected`
679 macro_rules! serialize_as {
680 ($name:ident: $data:expr => $expected:literal) => {
681 #[test]
682 fn $name() {
683 let mut buffer = String::new();
684 let ser = ContentSerializer {
685 writer: &mut buffer,
686 level: QuoteLevel::Full,
687 indent: Indent::Owned(Indentation::new(b' ', 2)),
688 write_indent: false,
689 expand_empty_elements: false,
690 };
691
692 $data.serialize(ser).unwrap();
693 assert_eq!(buffer, $expected);
694 }
695 };
696 }
697
698 /// Checks that attempt to serialize given `$data` results to a
699 /// serialization error `$kind` with `$reason`
700 macro_rules! err {
701 ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
702 #[test]
703 fn $name() {
704 let mut buffer = String::new();
705 let ser = ContentSerializer {
706 writer: &mut buffer,
707 level: QuoteLevel::Full,
708 indent: Indent::Owned(Indentation::new(b' ', 2)),
709 write_indent: false,
710 expand_empty_elements: false,
711 };
712
713 match $data.serialize(ser).unwrap_err() {
714 DeError::$kind(e) => assert_eq!(e, $reason),
715 e => panic!(
716 "Expected `{}({})`, found `{:?}`",
717 stringify!($kind),
718 $reason,
719 e
720 ),
721 }
722 // We can write something before fail
723 // assert_eq!(buffer, "");
724 }
725 };
726 }
727
728 serialize_as!(false_: false => "false");
729 serialize_as!(true_: true => "true");
730
731 serialize_as!(i8_: -42i8 => "-42");
732 serialize_as!(i16_: -4200i16 => "-4200");
733 serialize_as!(i32_: -42000000i32 => "-42000000");
734 serialize_as!(i64_: -42000000000000i64 => "-42000000000000");
735 serialize_as!(isize_: -42000000000000isize => "-42000000000000");
736
737 serialize_as!(u8_: 42u8 => "42");
738 serialize_as!(u16_: 4200u16 => "4200");
739 serialize_as!(u32_: 42000000u32 => "42000000");
740 serialize_as!(u64_: 42000000000000u64 => "42000000000000");
741 serialize_as!(usize_: 42000000000000usize => "42000000000000");
742
743 serde_if_integer128! {
744 serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
745 serialize_as!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000");
746 }
747
748 serialize_as!(f32_: 4.2f32 => "4.2");
749 serialize_as!(f64_: 4.2f64 => "4.2");
750
751 serialize_as!(char_non_escaped: 'h' => "h");
752 serialize_as!(char_lt: '<' => "&lt;");
753 serialize_as!(char_gt: '>' => "&gt;");
754 serialize_as!(char_amp: '&' => "&amp;");
755 serialize_as!(char_apos: '\'' => "&apos;");
756 serialize_as!(char_quot: '"' => "&quot;");
757 //TODO: add a setting to escape leading/trailing spaces, in order to
758 // pretty-print does not change the content
759 serialize_as!(char_space: ' ' => " ");
760
761 serialize_as!(str_non_escaped: "non-escaped string" => "non-escaped string");
762 serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
763
764 err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("`serialize_bytes` not supported yet"));
765
766 serialize_as!(option_none: Option::<Enum>::None => "");
767 serialize_as!(option_some: Some(Enum::Unit) => "<Unit/>");
768
769 serialize_as!(unit: () => "");
770 serialize_as!(unit_struct: Unit => "");
771 serialize_as!(unit_struct_escaped: UnitEscaped => "");
772
773 // Unlike SimpleTypeSerializer, enumeration values serialized as tags
774 serialize_as!(enum_unit: Enum::Unit => "<Unit/>");
775 err!(enum_unit_escaped: Enum::UnitEscaped
776 => Unsupported("character `<` is not allowed at the start of an XML name `<\"&'>`"));
777
778 // Newtypes recursively applies ContentSerializer
779 serialize_as!(newtype: Newtype(42) => "42");
780 serialize_as!(enum_newtype: Enum::Newtype(42) => "<Newtype>42</Newtype>");
781
782 // Note that sequences of primitives serialized without delimiters other that indent!
783 serialize_as!(seq: vec![1, 2, 3]
784 => "1\n\
785 2\n\
786 3");
787 serialize_as!(seq_empty: Vec::<usize>::new() => "");
788 serialize_as!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
789 => "&lt;&quot;&amp;&apos;&gt;\n\
790 with\t\r\n spaces\n\
791 3");
792 serialize_as!(tuple_struct: Tuple("first", 42)
793 => "first\n\
794 42");
795 serialize_as!(enum_tuple: Enum::Tuple("first", 42)
796 => "<Tuple>first</Tuple>\n\
797 <Tuple>42</Tuple>");
798
799 // Structured types cannot be serialized without surrounding tag, which
800 // only `enum` can provide
801 err!(map: BTreeMap::from([("_1", 2), ("_3", 4)])
802 => Unsupported("serialization of map types is not supported in `$value` field"));
803 err!(struct_: Struct { key: "answer", val: (42, 42) }
804 => Unsupported("serialization of struct `Struct` is not supported in `$value` field"));
805 serialize_as!(enum_struct: Enum::Struct { key: "answer", val: (42, 42) }
806 => "<Struct>\n \
807 <key>answer</key>\n \
808 <val>42</val>\n \
809 <val>42</val>\n\
810 </Struct>");
811
812 /// Special field name `$text` should be serialized as text content
813 mod text {
814 use super::*;
815 use pretty_assertions::assert_eq;
816
817 err!(map: BTreeMap::from([("$text", 2), ("_3", 4)])
818 => Unsupported("serialization of map types is not supported in `$value` field"));
819 err!(struct_:
820 Text {
821 before: "answer",
822 content: (42, 42),
823 after: "answer",
824 }
825 => Unsupported("serialization of struct `Text` is not supported in `$value` field"));
826 serialize_as!(enum_struct:
827 SpecialEnum::Text {
828 before: "answer",
829 content: (42, 42),
830 after: "answer",
831 }
832 => "<Text>\n \
833 <before>answer</before>\n \
834 42 42\n \
835 <after>answer</after>\n\
836 </Text>");
837 }
838
839 mod attributes {
840 use super::*;
841 use pretty_assertions::assert_eq;
842
843 err!(map_attr: BTreeMap::from([("@key1", 1), ("@key2", 2)])
844 => Unsupported("serialization of map types is not supported in `$value` field"));
845 err!(map_mixed: BTreeMap::from([("@key1", 1), ("key2", 2)])
846 => Unsupported("serialization of map types is not supported in `$value` field"));
847
848 err!(struct_: Attributes { key: "answer", val: (42, 42) }
849 => Unsupported("serialization of struct `Attributes` is not supported in `$value` field"));
850 err!(struct_before: AttributesBefore { key: "answer", val: 42 }
851 => Unsupported("serialization of struct `AttributesBefore` is not supported in `$value` field"));
852 err!(struct_after: AttributesAfter { key: "answer", val: 42 }
853 => Unsupported("serialization of struct `AttributesAfter` is not supported in `$value` field"));
854
855 serialize_as!(enum_: Enum::Attributes { key: "answer", val: (42, 42) }
856 => r#"<Attributes key="answer" val="42 42"/>"#);
857 serialize_as!(enum_before: Enum::AttributesBefore { key: "answer", val: 42 }
858 => "<AttributesBefore key=\"answer\">\n \
859 <val>42</val>\n\
860 </AttributesBefore>");
861 serialize_as!(enum_after: Enum::AttributesAfter { key: "answer", val: 42 }
862 => "<AttributesAfter val=\"42\">\n \
863 <key>answer</key>\n\
864 </AttributesAfter>");
865 }
866 }
867}
868