quick_xml/se/mod.rs
1//! Module to handle custom serde `Serializer`
2
3/// Implements writing primitives to the underlying writer.
4/// Implementor must provide `write_str(self, &str) -> Result<(), DeError>` method
5macro_rules! write_primitive {
6 ($method:ident ( $ty:ty )) => {
7 fn $method(mut self, value: $ty) -> Result<Self::Ok, Self::Error> {
8 self.write_str(&value.to_string())?;
9 Ok(self.writer)
10 }
11 };
12 () => {
13 fn serialize_bool(mut self, value: bool) -> Result<Self::Ok, Self::Error> {
14 self.write_str(if value { "true" } else { "false" })?;
15 Ok(self.writer)
16 }
17
18 write_primitive!(serialize_i8(i8));
19 write_primitive!(serialize_i16(i16));
20 write_primitive!(serialize_i32(i32));
21 write_primitive!(serialize_i64(i64));
22
23 write_primitive!(serialize_u8(u8));
24 write_primitive!(serialize_u16(u16));
25 write_primitive!(serialize_u32(u32));
26 write_primitive!(serialize_u64(u64));
27
28 serde_if_integer128! {
29 write_primitive!(serialize_i128(i128));
30 write_primitive!(serialize_u128(u128));
31 }
32
33 write_primitive!(serialize_f32(f32));
34 write_primitive!(serialize_f64(f64));
35
36 fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
37 self.serialize_str(&value.to_string())
38 }
39
40 fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
41 //TODO: customization point - allow user to decide how to encode bytes
42 Err(DeError::Unsupported(
43 "`serialize_bytes` not supported yet".into(),
44 ))
45 }
46
47 fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
48 Ok(self.writer)
49 }
50
51 fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
52 value.serialize(self)
53 }
54
55 fn serialize_unit_variant(
56 self,
57 _name: &'static str,
58 _variant_index: u32,
59 variant: &'static str,
60 ) -> Result<Self::Ok, Self::Error> {
61 self.serialize_str(variant)
62 }
63
64 fn serialize_newtype_struct<T: ?Sized + Serialize>(
65 self,
66 _name: &'static str,
67 value: &T,
68 ) -> Result<Self::Ok, Self::Error> {
69 value.serialize(self)
70 }
71 };
72}
73
74////////////////////////////////////////////////////////////////////////////////////////////////////
75
76mod content;
77mod element;
78pub(crate) mod key;
79pub(crate) mod simple_type;
80mod text;
81
82use self::content::ContentSerializer;
83use self::element::{ElementSerializer, Map, Struct, Tuple};
84use crate::de::TEXT_KEY;
85use crate::errors::serialize::DeError;
86use crate::writer::Indentation;
87use serde::ser::{self, Serialize};
88use serde::serde_if_integer128;
89use std::fmt::Write;
90use std::str::from_utf8;
91
92/// Serialize struct into a `Write`r.
93///
94/// # Examples
95///
96/// ```
97/// # use quick_xml::se::to_writer;
98/// # use serde::Serialize;
99/// # use pretty_assertions::assert_eq;
100/// #[derive(Serialize)]
101/// struct Root<'a> {
102/// #[serde(rename = "@attribute")]
103/// attribute: &'a str,
104/// element: &'a str,
105/// #[serde(rename = "$text")]
106/// text: &'a str,
107/// }
108///
109/// let data = Root {
110/// attribute: "attribute content",
111/// element: "element content",
112/// text: "text content",
113/// };
114///
115/// let mut buffer = String::new();
116/// to_writer(&mut buffer, &data).unwrap();
117/// assert_eq!(
118/// buffer,
119/// // The root tag name is automatically deduced from the struct name
120/// // This will not work for other types or struct with #[serde(flatten)] fields
121/// "<Root attribute=\"attribute content\">\
122/// <element>element content</element>\
123/// text content\
124/// </Root>"
125/// );
126/// ```
127pub fn to_writer<W, T>(mut writer: W, value: &T) -> Result<(), DeError>
128where
129 W: Write,
130 T: ?Sized + Serialize,
131{
132 value.serialize(Serializer::new(&mut writer))
133}
134
135/// Serialize struct into a `String`.
136///
137/// # Examples
138///
139/// ```
140/// # use quick_xml::se::to_string;
141/// # use serde::Serialize;
142/// # use pretty_assertions::assert_eq;
143/// #[derive(Serialize)]
144/// struct Root<'a> {
145/// #[serde(rename = "@attribute")]
146/// attribute: &'a str,
147/// element: &'a str,
148/// #[serde(rename = "$text")]
149/// text: &'a str,
150/// }
151///
152/// let data = Root {
153/// attribute: "attribute content",
154/// element: "element content",
155/// text: "text content",
156/// };
157///
158/// assert_eq!(
159/// to_string(&data).unwrap(),
160/// // The root tag name is automatically deduced from the struct name
161/// // This will not work for other types or struct with #[serde(flatten)] fields
162/// "<Root attribute=\"attribute content\">\
163/// <element>element content</element>\
164/// text content\
165/// </Root>"
166/// );
167/// ```
168pub fn to_string<T>(value: &T) -> Result<String, DeError>
169where
170 T: ?Sized + Serialize,
171{
172 let mut buffer = String::new();
173 to_writer(&mut buffer, value)?;
174 Ok(buffer)
175}
176
177/// Serialize struct into a `Write`r using specified root tag name.
178/// `root_tag` should be valid [XML name], otherwise error is returned.
179///
180/// # Examples
181///
182/// ```
183/// # use quick_xml::se::to_writer_with_root;
184/// # use serde::Serialize;
185/// # use pretty_assertions::assert_eq;
186/// #[derive(Serialize)]
187/// struct Root<'a> {
188/// #[serde(rename = "@attribute")]
189/// attribute: &'a str,
190/// element: &'a str,
191/// #[serde(rename = "$text")]
192/// text: &'a str,
193/// }
194///
195/// let data = Root {
196/// attribute: "attribute content",
197/// element: "element content",
198/// text: "text content",
199/// };
200///
201/// let mut buffer = String::new();
202/// to_writer_with_root(&mut buffer, "top-level", &data).unwrap();
203/// assert_eq!(
204/// buffer,
205/// "<top-level attribute=\"attribute content\">\
206/// <element>element content</element>\
207/// text content\
208/// </top-level>"
209/// );
210/// ```
211///
212/// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
213pub fn to_writer_with_root<W, T>(mut writer: W, root_tag: &str, value: &T) -> Result<(), DeError>
214where
215 W: Write,
216 T: ?Sized + Serialize,
217{
218 value.serialize(Serializer::with_root(&mut writer, Some(root_tag))?)
219}
220
221/// Serialize struct into a `String` using specified root tag name.
222/// `root_tag` should be valid [XML name], otherwise error is returned.
223///
224/// # Examples
225///
226/// ```
227/// # use quick_xml::se::to_string_with_root;
228/// # use serde::Serialize;
229/// # use pretty_assertions::assert_eq;
230/// #[derive(Serialize)]
231/// struct Root<'a> {
232/// #[serde(rename = "@attribute")]
233/// attribute: &'a str,
234/// element: &'a str,
235/// #[serde(rename = "$text")]
236/// text: &'a str,
237/// }
238///
239/// let data = Root {
240/// attribute: "attribute content",
241/// element: "element content",
242/// text: "text content",
243/// };
244///
245/// assert_eq!(
246/// to_string_with_root("top-level", &data).unwrap(),
247/// "<top-level attribute=\"attribute content\">\
248/// <element>element content</element>\
249/// text content\
250/// </top-level>"
251/// );
252/// ```
253///
254/// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
255pub fn to_string_with_root<T>(root_tag: &str, value: &T) -> Result<String, DeError>
256where
257 T: ?Sized + Serialize,
258{
259 let mut buffer = String::new();
260 to_writer_with_root(&mut buffer, root_tag, value)?;
261 Ok(buffer)
262}
263
264////////////////////////////////////////////////////////////////////////////////////////////////////
265
266/// Defines which characters would be escaped in [`Text`] events and attribute
267/// values.
268///
269/// [`Text`]: crate::events::Event::Text
270#[derive(Debug, Clone, Copy, PartialEq, Eq)]
271pub enum QuoteLevel {
272 /// Performs escaping, escape all characters that could have special meaning
273 /// in the XML. This mode is compatible with SGML specification.
274 ///
275 /// Characters that will be replaced:
276 ///
277 /// Original | Replacement
278 /// ---------|------------
279 /// `<` | `<`
280 /// `>` | `>`
281 /// `&` | `&`
282 /// `"` | `"`
283 /// `'` | `'`
284 Full,
285 /// Performs escaping that is compatible with SGML specification.
286 ///
287 /// This level adds escaping of `>` to the `Minimal` level, which is [required]
288 /// for compatibility with SGML.
289 ///
290 /// Characters that will be replaced:
291 ///
292 /// Original | Replacement
293 /// ---------|------------
294 /// `<` | `<`
295 /// `>` | `>`
296 /// `&` | `&`
297 ///
298 /// [required]: https://www.w3.org/TR/xml11/#syntax
299 Partial,
300 /// Performs the minimal possible escaping, escape only strictly necessary
301 /// characters.
302 ///
303 /// Characters that will be replaced:
304 ///
305 /// Original | Replacement
306 /// ---------|------------
307 /// `<` | `<`
308 /// `&` | `&`
309 Minimal,
310}
311
312////////////////////////////////////////////////////////////////////////////////////////////////////
313
314/// Implements serialization method by forwarding it to the serializer created by
315/// the helper method [`Serializer::ser`].
316macro_rules! forward {
317 ($name:ident($ty:ty)) => {
318 fn $name(self, value: $ty) -> Result<Self::Ok, Self::Error> {
319 self.ser(&concat!("`", stringify!($ty), "`"))?.$name(value)
320 }
321 };
322}
323
324////////////////////////////////////////////////////////////////////////////////////////////////////
325
326/// Almost all characters can form a name. Citation from <https://www.w3.org/TR/xml11/#sec-xml11>:
327///
328/// > The overall philosophy of names has changed since XML 1.0. Whereas XML 1.0
329/// > provided a rigid definition of names, wherein everything that was not permitted
330/// > was forbidden, XML 1.1 names are designed so that everything that is not
331/// > forbidden (for a specific reason) is permitted. Since Unicode will continue
332/// > to grow past version 4.0, further changes to XML can be avoided by allowing
333/// > almost any character, including those not yet assigned, in names.
334///
335/// <https://www.w3.org/TR/xml11/#NT-NameStartChar>
336const fn is_xml11_name_start_char(ch: char) -> bool {
337 match ch {
338 ':'
339 | 'A'..='Z'
340 | '_'
341 | 'a'..='z'
342 | '\u{00C0}'..='\u{00D6}'
343 | '\u{00D8}'..='\u{00F6}'
344 | '\u{00F8}'..='\u{02FF}'
345 | '\u{0370}'..='\u{037D}'
346 | '\u{037F}'..='\u{1FFF}'
347 | '\u{200C}'..='\u{200D}'
348 | '\u{2070}'..='\u{218F}'
349 | '\u{2C00}'..='\u{2FEF}'
350 | '\u{3001}'..='\u{D7FF}'
351 | '\u{F900}'..='\u{FDCF}'
352 | '\u{FDF0}'..='\u{FFFD}'
353 | '\u{10000}'..='\u{EFFFF}' => true,
354 _ => false,
355 }
356}
357/// <https://www.w3.org/TR/xml11/#NT-NameChar>
358const fn is_xml11_name_char(ch: char) -> bool {
359 match ch {
360 '-' | '.' | '0'..='9' | '\u{00B7}' | '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}' => {
361 true
362 }
363 _ => is_xml11_name_start_char(ch),
364 }
365}
366
367/// Helper struct to self-defense from errors
368#[derive(Clone, Copy, Debug, PartialEq)]
369pub(self) struct XmlName<'n>(&'n str);
370
371impl<'n> XmlName<'n> {
372 /// Checks correctness of the XML name according to [XML 1.1 specification]
373 ///
374 /// [XML 1.1 specification]: https://www.w3.org/TR/xml11/#NT-Name
375 pub fn try_from(name: &'n str) -> Result<XmlName<'n>, DeError> {
376 //TODO: Customization point: allow user to decide if he want to reject or encode the name
377 match name.chars().next() {
378 Some(ch) if !is_xml11_name_start_char(ch) => Err(DeError::Unsupported(
379 format!("character `{ch}` is not allowed at the start of an XML name `{name}`")
380 .into(),
381 )),
382 _ => match name.matches(|ch| !is_xml11_name_char(ch)).next() {
383 Some(s) => Err(DeError::Unsupported(
384 format!("character `{s}` is not allowed in an XML name `{name}`").into(),
385 )),
386 None => Ok(XmlName(name)),
387 },
388 }
389 }
390}
391
392////////////////////////////////////////////////////////////////////////////////////////////////////
393
394pub(crate) enum Indent<'i> {
395 /// No indent should be written before the element
396 None,
397 /// The specified indent should be written. The type owns the buffer with indent
398 Owned(Indentation),
399 /// The specified indent should be written. The type borrows buffer with indent
400 /// from its owner
401 Borrow(&'i mut Indentation),
402}
403
404impl<'i> Indent<'i> {
405 pub fn borrow(&mut self) -> Indent {
406 match self {
407 Self::None => Indent::None,
408 Self::Owned(ref mut i) => Indent::Borrow(i),
409 Self::Borrow(i) => Indent::Borrow(i),
410 }
411 }
412
413 pub fn increase(&mut self) {
414 match self {
415 Self::None => {}
416 Self::Owned(i) => i.grow(),
417 Self::Borrow(i) => i.grow(),
418 }
419 }
420
421 pub fn decrease(&mut self) {
422 match self {
423 Self::None => {}
424 Self::Owned(i) => i.shrink(),
425 Self::Borrow(i) => i.shrink(),
426 }
427 }
428
429 pub fn write_indent<W: std::fmt::Write>(&mut self, mut writer: W) -> Result<(), DeError> {
430 match self {
431 Self::None => {}
432 Self::Owned(i) => {
433 writer.write_char('\n')?;
434 writer.write_str(from_utf8(i.current())?)?;
435 }
436 Self::Borrow(i) => {
437 writer.write_char('\n')?;
438 writer.write_str(from_utf8(i.current())?)?;
439 }
440 }
441 Ok(())
442 }
443}
444
445////////////////////////////////////////////////////////////////////////////////////////////////////
446
447/// A Serializer
448pub struct Serializer<'w, 'r, W: Write> {
449 ser: ContentSerializer<'w, 'r, W>,
450 /// Name of the root tag. If not specified, deduced from the structure name
451 root_tag: Option<XmlName<'r>>,
452}
453
454impl<'w, 'r, W: Write> Serializer<'w, 'r, W> {
455 /// Creates a new `Serializer` that uses struct name as a root tag name.
456 ///
457 /// Note, that attempt to serialize a non-struct (including unit structs
458 /// and newtype structs) will end up to an error. Use `with_root` to create
459 /// serializer with explicitly defined root element name
460 pub fn new(writer: &'w mut W) -> Self {
461 Self {
462 ser: ContentSerializer {
463 writer,
464 level: QuoteLevel::Partial,
465 indent: Indent::None,
466 write_indent: false,
467 expand_empty_elements: false,
468 },
469 root_tag: None,
470 }
471 }
472
473 /// Creates a new `Serializer` that uses specified root tag name. `name` should
474 /// be valid [XML name], otherwise error is returned.
475 ///
476 /// # Examples
477 ///
478 /// When serializing a primitive type, only its representation will be written:
479 ///
480 /// ```
481 /// # use pretty_assertions::assert_eq;
482 /// # use serde::Serialize;
483 /// # use quick_xml::se::Serializer;
484 ///
485 /// let mut buffer = String::new();
486 /// let ser = Serializer::with_root(&mut buffer, Some("root")).unwrap();
487 ///
488 /// "node".serialize(ser).unwrap();
489 /// assert_eq!(buffer, "<root>node</root>");
490 /// ```
491 ///
492 /// When serializing a struct, newtype struct, unit struct or tuple `root_tag`
493 /// is used as tag name of root(s) element(s):
494 ///
495 /// ```
496 /// # use pretty_assertions::assert_eq;
497 /// # use serde::Serialize;
498 /// # use quick_xml::se::Serializer;
499 ///
500 /// #[derive(Debug, PartialEq, Serialize)]
501 /// struct Struct {
502 /// question: String,
503 /// answer: u32,
504 /// }
505 ///
506 /// let mut buffer = String::new();
507 /// let ser = Serializer::with_root(&mut buffer, Some("root")).unwrap();
508 ///
509 /// let data = Struct {
510 /// question: "The Ultimate Question of Life, the Universe, and Everything".into(),
511 /// answer: 42,
512 /// };
513 ///
514 /// data.serialize(ser).unwrap();
515 /// assert_eq!(
516 /// buffer,
517 /// "<root>\
518 /// <question>The Ultimate Question of Life, the Universe, and Everything</question>\
519 /// <answer>42</answer>\
520 /// </root>"
521 /// );
522 /// ```
523 ///
524 /// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
525 pub fn with_root(writer: &'w mut W, root_tag: Option<&'r str>) -> Result<Self, DeError> {
526 Ok(Self {
527 ser: ContentSerializer {
528 writer,
529 level: QuoteLevel::Partial,
530 indent: Indent::None,
531 write_indent: false,
532 expand_empty_elements: false,
533 },
534 root_tag: root_tag.map(|tag| XmlName::try_from(tag)).transpose()?,
535 })
536 }
537
538 /// Enable or disable expansion of empty elements. Defaults to `false`.
539 ///
540 /// # Examples
541 ///
542 /// ```
543 /// # use pretty_assertions::assert_eq;
544 /// # use serde::Serialize;
545 /// # use quick_xml::se::Serializer;
546 ///
547 /// #[derive(Debug, PartialEq, Serialize)]
548 /// struct Struct {
549 /// question: Option<String>,
550 /// }
551 ///
552 /// let mut buffer = String::new();
553 /// let mut ser = Serializer::new(&mut buffer);
554 /// ser.expand_empty_elements(true);
555 ///
556 /// let data = Struct {
557 /// question: None,
558 /// };
559 ///
560 /// data.serialize(ser).unwrap();
561 /// assert_eq!(
562 /// buffer,
563 /// "<Struct><question></question></Struct>"
564 /// );
565 /// ```
566 pub fn expand_empty_elements(&mut self, expand: bool) -> &mut Self {
567 self.ser.expand_empty_elements = expand;
568 self
569 }
570
571 /// Configure indent for a serializer
572 pub fn indent(&mut self, indent_char: char, indent_size: usize) -> &mut Self {
573 self.ser.indent = Indent::Owned(Indentation::new(indent_char as u8, indent_size));
574 self
575 }
576
577 /// Set the level of quoting used when writing texts
578 ///
579 /// Default: [`QuoteLevel::Minimal`]
580 pub fn set_quote_level(&mut self, level: QuoteLevel) -> &mut Self {
581 self.ser.level = level;
582 self
583 }
584
585 /// Set the indent object for a serializer
586 pub(crate) fn set_indent(&mut self, indent: Indent<'r>) -> &mut Self {
587 self.ser.indent = indent;
588 self
589 }
590
591 /// Creates actual serializer or returns an error if root tag is not defined.
592 /// In that case `err` contains the name of type that cannot be serialized.
593 fn ser(self, err: &str) -> Result<ElementSerializer<'w, 'r, W>, DeError> {
594 if let Some(key) = self.root_tag {
595 Ok(ElementSerializer { ser: self.ser, key })
596 } else {
597 Err(DeError::Unsupported(
598 format!("cannot serialize {} without defined root tag", err).into(),
599 ))
600 }
601 }
602
603 /// Creates actual serializer using root tag or a specified `key` if root tag
604 /// is not defined. Returns an error if root tag is not defined and a `key`
605 /// does not conform [XML rules](XmlName::try_from) for names.
606 fn ser_name(self, key: &'static str) -> Result<ElementSerializer<'w, 'r, W>, DeError> {
607 Ok(ElementSerializer {
608 ser: self.ser,
609 key: match self.root_tag {
610 Some(key) => key,
611 None => XmlName::try_from(key)?,
612 },
613 })
614 }
615}
616
617impl<'w, 'r, W: Write> ser::Serializer for Serializer<'w, 'r, W> {
618 type Ok = ();
619 type Error = DeError;
620
621 type SerializeSeq = ElementSerializer<'w, 'r, W>;
622 type SerializeTuple = ElementSerializer<'w, 'r, W>;
623 type SerializeTupleStruct = ElementSerializer<'w, 'r, W>;
624 type SerializeTupleVariant = Tuple<'w, 'r, W>;
625 type SerializeMap = Map<'w, 'r, W>;
626 type SerializeStruct = Struct<'w, 'r, W>;
627 type SerializeStructVariant = Struct<'w, 'r, W>;
628
629 forward!(serialize_bool(bool));
630
631 forward!(serialize_i8(i8));
632 forward!(serialize_i16(i16));
633 forward!(serialize_i32(i32));
634 forward!(serialize_i64(i64));
635
636 forward!(serialize_u8(u8));
637 forward!(serialize_u16(u16));
638 forward!(serialize_u32(u32));
639 forward!(serialize_u64(u64));
640
641 serde_if_integer128! {
642 forward!(serialize_i128(i128));
643 forward!(serialize_u128(u128));
644 }
645
646 forward!(serialize_f32(f32));
647 forward!(serialize_f64(f64));
648
649 forward!(serialize_char(char));
650 forward!(serialize_str(&str));
651 forward!(serialize_bytes(&[u8]));
652
653 fn serialize_none(self) -> Result<Self::Ok, DeError> {
654 Ok(())
655 }
656
657 fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, DeError> {
658 value.serialize(self)
659 }
660
661 fn serialize_unit(self) -> Result<Self::Ok, DeError> {
662 self.ser("`()`")?.serialize_unit()
663 }
664
665 fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, DeError> {
666 self.ser_name(name)?.serialize_unit_struct(name)
667 }
668
669 fn serialize_unit_variant(
670 self,
671 name: &'static str,
672 _variant_index: u32,
673 variant: &'static str,
674 ) -> Result<Self::Ok, DeError> {
675 if variant == TEXT_KEY {
676 // We should write some text but we don't known what text to write
677 Err(DeError::Unsupported(
678 format!(
679 "cannot serialize enum unit variant `{}::$text` as text content value",
680 name
681 )
682 .into(),
683 ))
684 } else {
685 let name = XmlName::try_from(variant)?;
686 self.ser.write_empty(name)
687 }
688 }
689
690 fn serialize_newtype_struct<T: ?Sized + Serialize>(
691 self,
692 name: &'static str,
693 value: &T,
694 ) -> Result<Self::Ok, DeError> {
695 self.ser_name(name)?.serialize_newtype_struct(name, value)
696 }
697
698 fn serialize_newtype_variant<T: ?Sized + Serialize>(
699 self,
700 _name: &'static str,
701 _variant_index: u32,
702 variant: &'static str,
703 value: &T,
704 ) -> Result<Self::Ok, DeError> {
705 if variant == TEXT_KEY {
706 value.serialize(self.ser.into_simple_type_serializer())?;
707 Ok(())
708 } else {
709 let ser = ElementSerializer {
710 ser: self.ser,
711 key: XmlName::try_from(variant)?,
712 };
713 value.serialize(ser)
714 }
715 }
716
717 fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, DeError> {
718 self.ser("sequence")?.serialize_seq(len)
719 }
720
721 fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, DeError> {
722 self.ser("unnamed tuple")?.serialize_tuple(len)
723 }
724
725 fn serialize_tuple_struct(
726 self,
727 name: &'static str,
728 len: usize,
729 ) -> Result<Self::SerializeTupleStruct, DeError> {
730 self.ser_name(name)?.serialize_tuple_struct(name, len)
731 }
732
733 fn serialize_tuple_variant(
734 self,
735 name: &'static str,
736 _variant_index: u32,
737 variant: &'static str,
738 len: usize,
739 ) -> Result<Self::SerializeTupleVariant, DeError> {
740 if variant == TEXT_KEY {
741 self.ser
742 .into_simple_type_serializer()
743 .serialize_tuple_struct(name, len)
744 .map(Tuple::Text)
745 } else {
746 let ser = ElementSerializer {
747 ser: self.ser,
748 key: XmlName::try_from(variant)?,
749 };
750 ser.serialize_tuple_struct(name, len).map(Tuple::Element)
751 }
752 }
753
754 fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, DeError> {
755 self.ser("map")?.serialize_map(len)
756 }
757
758 fn serialize_struct(
759 self,
760 name: &'static str,
761 len: usize,
762 ) -> Result<Self::SerializeStruct, DeError> {
763 self.ser_name(name)?.serialize_struct(name, len)
764 }
765
766 fn serialize_struct_variant(
767 self,
768 name: &'static str,
769 _variant_index: u32,
770 variant: &'static str,
771 len: usize,
772 ) -> Result<Self::SerializeStructVariant, DeError> {
773 if variant == TEXT_KEY {
774 Err(DeError::Unsupported(
775 format!(
776 "cannot serialize enum struct variant `{}::$text` as text content value",
777 name
778 )
779 .into(),
780 ))
781 } else {
782 let ser = ElementSerializer {
783 ser: self.ser,
784 key: XmlName::try_from(variant)?,
785 };
786 ser.serialize_struct(name, len)
787 }
788 }
789}
790
791#[cfg(test)]
792mod quote_level {
793 use super::*;
794 use pretty_assertions::assert_eq;
795 use serde::Serialize;
796
797 #[derive(Debug, PartialEq, Serialize)]
798 struct Element(&'static str);
799
800 #[derive(Debug, PartialEq, Serialize)]
801 struct Example {
802 #[serde(rename = "@attribute")]
803 attribute: &'static str,
804 element: Element,
805 }
806
807 #[test]
808 fn default_() {
809 let example = Example {
810 attribute: "special chars: &, <, >, \", '",
811 element: Element("special chars: &, <, >, \", '"),
812 };
813
814 let mut buffer = String::new();
815 let ser = Serializer::new(&mut buffer);
816
817 example.serialize(ser).unwrap();
818 assert_eq!(
819 buffer,
820 "<Example attribute=\"special chars: &, <, >, ", '\">\
821 <element>special chars: &, <, >, \", '</element>\
822 </Example>"
823 );
824 }
825
826 #[test]
827 fn minimal() {
828 let example = Example {
829 attribute: "special chars: &, <, >, \", '",
830 element: Element("special chars: &, <, >, \", '"),
831 };
832
833 let mut buffer = String::new();
834 let mut ser = Serializer::new(&mut buffer);
835 ser.set_quote_level(QuoteLevel::Minimal);
836
837 example.serialize(ser).unwrap();
838 assert_eq!(
839 buffer,
840 "<Example attribute=\"special chars: &, <, >, ", '\">\
841 <element>special chars: &, <, >, \", '</element>\
842 </Example>"
843 );
844 }
845
846 #[test]
847 fn partial() {
848 let example = Example {
849 attribute: "special chars: &, <, >, \", '",
850 element: Element("special chars: &, <, >, \", '"),
851 };
852
853 let mut buffer = String::new();
854 let mut ser = Serializer::new(&mut buffer);
855 ser.set_quote_level(QuoteLevel::Partial);
856
857 example.serialize(ser).unwrap();
858 assert_eq!(
859 buffer,
860 "<Example attribute=\"special chars: &, <, >, ", '\">\
861 <element>special chars: &, <, >, \", '</element>\
862 </Example>"
863 );
864 }
865
866 #[test]
867 fn full() {
868 let example = Example {
869 attribute: "special chars: &, <, >, \", '",
870 element: Element("special chars: &, <, >, \", '"),
871 };
872
873 let mut buffer = String::new();
874 let mut ser = Serializer::new(&mut buffer);
875 ser.set_quote_level(QuoteLevel::Full);
876
877 example.serialize(ser).unwrap();
878 assert_eq!(
879 buffer,
880 "<Example attribute=\"special chars: &, <, >, ", '\">\
881 <element>special chars: &, <, >, ", '</element>\
882 </Example>"
883 );
884 }
885}