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_fmt(format_args!("{}", value))?;
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.encode_utf8(&mut [0u8; 4]))
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(Self::Error::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::writer::{Indentation, ToFmtWrite};
86use serde::ser::{self, Serialize};
87use serde::serde_if_integer128;
88use std::fmt::Write;
89use std::str::from_utf8;
90
91pub use self::simple_type::SimpleTypeSerializer;
92pub use crate::errors::serialize::SeError;
93
94/// Serialize struct into a `Write`r.
95///
96/// Returns the classification of the last written type.
97///
98/// # Examples
99///
100/// ```
101/// # use quick_xml::se::to_writer;
102/// # use serde::Serialize;
103/// # use pretty_assertions::assert_eq;
104/// #[derive(Serialize)]
105/// struct Root<'a> {
106///     #[serde(rename = "@attribute")]
107///     attribute: &'a str,
108///     element: &'a str,
109///     #[serde(rename = "$text")]
110///     text: &'a str,
111/// }
112///
113/// let data = Root {
114///     attribute: "attribute content",
115///     element: "element content",
116///     text: "text content",
117/// };
118///
119/// let mut buffer = String::new();
120/// to_writer(&mut buffer, &data).unwrap();
121/// assert_eq!(
122///     buffer,
123///     // The root tag name is automatically deduced from the struct name
124///     // This will not work for other types or struct with #[serde(flatten)] fields
125///     "<Root attribute=\"attribute content\">\
126///         <element>element content</element>\
127///         text content\
128///     </Root>"
129/// );
130/// ```
131pub fn to_writer<W, T>(mut writer: W, value: &T) -> Result<WriteResult, SeError>
132where
133    W: Write,
134    T: ?Sized + Serialize,
135{
136    value.serialize(Serializer::new(&mut writer))
137}
138
139/// Serialize struct into a `io::Write`r restricted to utf-8 encoding.
140///
141/// Returns the classification of the last written type.
142///
143/// # Examples
144///
145/// ```
146/// # use quick_xml::se::to_utf8_io_writer;
147/// # use serde::Serialize;
148/// # use pretty_assertions::assert_eq;
149/// # use std::io::BufWriter;
150/// #[derive(Serialize)]
151/// struct Root<'a> {
152///     #[serde(rename = "@attribute")]
153///     attribute: &'a str,
154///     element: &'a str,
155///     #[serde(rename = "$text")]
156///     text: &'a str,
157/// }
158///
159/// let data = Root {
160///     attribute: "attribute content",
161///     element: "element content",
162///     text: "text content",
163/// };
164///
165/// let mut buffer = Vec::new();
166/// to_utf8_io_writer(&mut BufWriter::new(&mut buffer), &data).unwrap();
167///
168/// assert_eq!(
169///     std::str::from_utf8(&buffer).unwrap(),
170///     // The root tag name is automatically deduced from the struct name
171///     // This will not work for other types or struct with #[serde(flatten)] fields
172///     "<Root attribute=\"attribute content\">\
173///         <element>element content</element>\
174///         text content\
175///     </Root>"
176/// );
177/// ```
178pub fn to_utf8_io_writer<W, T>(writer: W, value: &T) -> Result<WriteResult, SeError>
179where
180    W: std::io::Write,
181    T: ?Sized + Serialize,
182{
183    value.serialize(Serializer::new(&mut ToFmtWrite(writer)))
184}
185
186/// Serialize struct into a `String`.
187///
188/// # Examples
189///
190/// ```
191/// # use quick_xml::se::to_string;
192/// # use serde::Serialize;
193/// # use pretty_assertions::assert_eq;
194/// #[derive(Serialize)]
195/// struct Root<'a> {
196///     #[serde(rename = "@attribute")]
197///     attribute: &'a str,
198///     element: &'a str,
199///     #[serde(rename = "$text")]
200///     text: &'a str,
201/// }
202///
203/// let data = Root {
204///     attribute: "attribute content",
205///     element: "element content",
206///     text: "text content",
207/// };
208///
209/// assert_eq!(
210///     to_string(&data).unwrap(),
211///     // The root tag name is automatically deduced from the struct name
212///     // This will not work for other types or struct with #[serde(flatten)] fields
213///     "<Root attribute=\"attribute content\">\
214///         <element>element content</element>\
215///         text content\
216///     </Root>"
217/// );
218/// ```
219pub fn to_string<T>(value: &T) -> Result<String, SeError>
220where
221    T: ?Sized + Serialize,
222{
223    let mut buffer = String::new();
224    to_writer(&mut buffer, value)?;
225    Ok(buffer)
226}
227
228/// Serialize struct into a `Write`r using specified root tag name.
229/// `root_tag` should be valid [XML name], otherwise error is returned.
230///
231/// Returns the classification of the last written type.
232///
233/// # Examples
234///
235/// ```
236/// # use quick_xml::se::to_writer_with_root;
237/// # use serde::Serialize;
238/// # use pretty_assertions::assert_eq;
239/// #[derive(Serialize)]
240/// struct Root<'a> {
241///     #[serde(rename = "@attribute")]
242///     attribute: &'a str,
243///     element: &'a str,
244///     #[serde(rename = "$text")]
245///     text: &'a str,
246/// }
247///
248/// let data = Root {
249///     attribute: "attribute content",
250///     element: "element content",
251///     text: "text content",
252/// };
253///
254/// let mut buffer = String::new();
255/// to_writer_with_root(&mut buffer, "top-level", &data).unwrap();
256/// assert_eq!(
257///     buffer,
258///     "<top-level attribute=\"attribute content\">\
259///         <element>element content</element>\
260///         text content\
261///     </top-level>"
262/// );
263/// ```
264///
265/// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
266pub fn to_writer_with_root<W, T>(
267    mut writer: W,
268    root_tag: &str,
269    value: &T,
270) -> Result<WriteResult, SeError>
271where
272    W: Write,
273    T: ?Sized + Serialize,
274{
275    value.serialize(Serializer::with_root(&mut writer, Some(root_tag))?)
276}
277
278/// Serialize struct into a `String` using specified root tag name.
279/// `root_tag` should be valid [XML name], otherwise error is returned.
280///
281/// # Examples
282///
283/// ```
284/// # use quick_xml::se::to_string_with_root;
285/// # use serde::Serialize;
286/// # use pretty_assertions::assert_eq;
287/// #[derive(Serialize)]
288/// struct Root<'a> {
289///     #[serde(rename = "@attribute")]
290///     attribute: &'a str,
291///     element: &'a str,
292///     #[serde(rename = "$text")]
293///     text: &'a str,
294/// }
295///
296/// let data = Root {
297///     attribute: "attribute content",
298///     element: "element content",
299///     text: "text content",
300/// };
301///
302/// assert_eq!(
303///     to_string_with_root("top-level", &data).unwrap(),
304///     "<top-level attribute=\"attribute content\">\
305///         <element>element content</element>\
306///         text content\
307///     </top-level>"
308/// );
309/// ```
310///
311/// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
312pub fn to_string_with_root<T>(root_tag: &str, value: &T) -> Result<String, SeError>
313where
314    T: ?Sized + Serialize,
315{
316    let mut buffer = String::new();
317    to_writer_with_root(&mut buffer, root_tag, value)?;
318    Ok(buffer)
319}
320
321////////////////////////////////////////////////////////////////////////////////////////////////////
322
323/// Defines the format for text content serialization
324#[derive(Debug, Clone, Copy, PartialEq, Eq)]
325#[non_exhaustive]
326pub enum TextFormat {
327    /// Serialize as regular text content with escaping
328    Text,
329    /// Serialize as CDATA section without escaping
330    CData,
331}
332
333/// Defines which characters would be escaped in [`Text`] events and attribute
334/// values.
335///
336/// [`Text`]: crate::events::Event::Text
337#[derive(Debug, Clone, Copy, PartialEq, Eq)]
338pub enum QuoteLevel {
339    /// Performs escaping, escape all characters that could have special meaning
340    /// in the XML. This mode is compatible with SGML specification.
341    ///
342    /// Characters that will be replaced:
343    ///
344    /// Original | Replacement
345    /// ---------|------------
346    /// `<`      | `&lt;`
347    /// `>`      | `&gt;`
348    /// `&`      | `&amp;`
349    /// `"`      | `&quot;`
350    /// `'`      | `&apos;`
351    Full,
352    /// Performs escaping that is compatible with SGML specification.
353    ///
354    /// This level adds escaping of `>` to the `Minimal` level, which is [required]
355    /// for compatibility with SGML.
356    ///
357    /// Characters that will be replaced:
358    ///
359    /// Original | Replacement
360    /// ---------|------------
361    /// `<`      | `&lt;`
362    /// `>`      | `&gt;`
363    /// `&`      | `&amp;`
364    ///
365    /// [required]: https://www.w3.org/TR/xml11/#syntax
366    Partial,
367    /// Performs the minimal possible escaping, escape only strictly necessary
368    /// characters.
369    ///
370    /// Characters that will be replaced:
371    ///
372    /// Original | Replacement
373    /// ---------|------------
374    /// `<`      | `&lt;`
375    /// `&`      | `&amp;`
376    Minimal,
377}
378
379/// Classification of the type written by the serializer.
380#[derive(Debug, Clone, Copy, PartialEq, Eq)]
381pub enum WriteResult {
382    /// Text with insignificant spaces was written, for example a number. Adding indent to the
383    /// serialized data does not change meaning of the data.
384    Text,
385    /// The XML tag was written. Adding indent to the serialized data does not change meaning of the data.
386    Element,
387    /// Nothing was written (i. e. serialized type not represented in XML a all). Adding indent to the
388    /// serialized data does not change meaning of the data. This is returned for units, unit structs
389    /// and unit variants.
390    Nothing,
391    /// Text with significant spaces was written, for example a string. Adding indent to the
392    /// serialized data may change meaning of the data.
393    SensitiveText,
394    /// `None` was serialized and nothing was written. `None` does not represented in XML,
395    /// but adding indent after it may change meaning of the data.
396    SensitiveNothing,
397}
398
399impl WriteResult {
400    /// Returns `true` if indent should be written after the object (if configured) and `false` otherwise.
401    #[inline]
402    pub fn allow_indent(&self) -> bool {
403        matches!(self, Self::Element | Self::Nothing)
404    }
405
406    /// Returns `true` if self is `Text` or `SensitiveText`.
407    #[inline]
408    pub fn is_text(&self) -> bool {
409        matches!(self, Self::Text | Self::SensitiveText)
410    }
411}
412
413////////////////////////////////////////////////////////////////////////////////////////////////////
414
415/// Implements serialization method by forwarding it to the serializer created by
416/// the helper method [`Serializer::ser`].
417macro_rules! forward {
418    ($name:ident($ty:ty)) => {
419        fn $name(self, value: $ty) -> Result<Self::Ok, Self::Error> {
420            self.ser(&concat!("`", stringify!($ty), "`"))?.$name(value)
421        }
422    };
423}
424
425////////////////////////////////////////////////////////////////////////////////////////////////////
426
427/// Almost all characters can form a name. Citation from <https://www.w3.org/TR/xml11/#sec-xml11>:
428///
429/// > The overall philosophy of names has changed since XML 1.0. Whereas XML 1.0
430/// > provided a rigid definition of names, wherein everything that was not permitted
431/// > was forbidden, XML 1.1 names are designed so that everything that is not
432/// > forbidden (for a specific reason) is permitted. Since Unicode will continue
433/// > to grow past version 4.0, further changes to XML can be avoided by allowing
434/// > almost any character, including those not yet assigned, in names.
435///
436/// <https://www.w3.org/TR/xml11/#NT-NameStartChar>
437const fn is_xml11_name_start_char(ch: char) -> bool {
438    // Not need to use macro when core primitives is enough
439    #[allow(clippy::match_like_matches_macro)]
440    match ch {
441        ':'
442        | 'A'..='Z'
443        | '_'
444        | 'a'..='z'
445        | '\u{00C0}'..='\u{00D6}'
446        | '\u{00D8}'..='\u{00F6}'
447        | '\u{00F8}'..='\u{02FF}'
448        | '\u{0370}'..='\u{037D}'
449        | '\u{037F}'..='\u{1FFF}'
450        | '\u{200C}'..='\u{200D}'
451        | '\u{2070}'..='\u{218F}'
452        | '\u{2C00}'..='\u{2FEF}'
453        | '\u{3001}'..='\u{D7FF}'
454        | '\u{F900}'..='\u{FDCF}'
455        | '\u{FDF0}'..='\u{FFFD}'
456        | '\u{10000}'..='\u{EFFFF}' => true,
457        _ => false,
458    }
459}
460/// <https://www.w3.org/TR/xml11/#NT-NameChar>
461const fn is_xml11_name_char(ch: char) -> bool {
462    match ch {
463        '-' | '.' | '0'..='9' | '\u{00B7}' | '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}' => {
464            true
465        }
466        _ => is_xml11_name_start_char(ch),
467    }
468}
469
470/// Helper struct to self-defense from errors
471#[derive(Clone, Copy, Debug, PartialEq)]
472struct XmlName<'n>(&'n str);
473
474impl<'n> XmlName<'n> {
475    /// Checks correctness of the XML name according to [XML 1.1 specification]
476    ///
477    /// [XML 1.1 specification]: https://www.w3.org/TR/xml11/#NT-Name
478    pub fn try_from(name: &'n str) -> Result<XmlName<'n>, SeError> {
479        //TODO: Customization point: allow user to decide if he want to reject or encode the name
480        match name.chars().next() {
481            Some(ch) if !is_xml11_name_start_char(ch) => Err(SeError::Unsupported(
482                format!("character `{ch}` is not allowed at the start of an XML name `{name}`")
483                    .into(),
484            )),
485            _ => match name.matches(|ch| !is_xml11_name_char(ch)).next() {
486                Some(s) => Err(SeError::Unsupported(
487                    format!("character `{s}` is not allowed in an XML name `{name}`").into(),
488                )),
489                None => Ok(XmlName(name)),
490            },
491        }
492    }
493}
494
495////////////////////////////////////////////////////////////////////////////////////////////////////
496
497pub(crate) enum Indent<'i> {
498    /// No indent should be written before the element
499    None,
500    /// The specified indent should be written. The type owns the buffer with indent
501    Owned(Indentation),
502    /// The specified indent should be written. The type borrows buffer with indent
503    /// from its owner
504    Borrow(&'i mut Indentation),
505}
506
507impl<'i> Indent<'i> {
508    pub fn borrow(&mut self) -> Indent<'_> {
509        match self {
510            Self::None => Indent::None,
511            Self::Owned(ref mut i) => Indent::Borrow(i),
512            Self::Borrow(i) => Indent::Borrow(i),
513        }
514    }
515
516    pub fn increase(&mut self) {
517        match self {
518            Self::None => {}
519            Self::Owned(i) => i.grow(),
520            Self::Borrow(i) => i.grow(),
521        }
522    }
523
524    pub fn decrease(&mut self) {
525        match self {
526            Self::None => {}
527            Self::Owned(i) => i.shrink(),
528            Self::Borrow(i) => i.shrink(),
529        }
530    }
531
532    pub fn write_indent<W: std::fmt::Write>(&mut self, mut writer: W) -> Result<(), SeError> {
533        match self {
534            Self::None => {}
535            Self::Owned(i) => {
536                writer.write_char('\n')?;
537                writer.write_str(from_utf8(i.current())?)?;
538            }
539            Self::Borrow(i) => {
540                writer.write_char('\n')?;
541                writer.write_str(from_utf8(i.current())?)?;
542            }
543        }
544        Ok(())
545    }
546}
547
548////////////////////////////////////////////////////////////////////////////////////////////////////
549
550/// A Serializer.
551///
552/// Returns the classification of the last written type.
553pub struct Serializer<'w, 'r, W: Write> {
554    ser: ContentSerializer<'w, 'r, W>,
555    /// Name of the root tag. If not specified, deduced from the structure name
556    root_tag: Option<XmlName<'r>>,
557}
558
559impl<'w, 'r, W: Write> Serializer<'w, 'r, W> {
560    /// Creates a new `Serializer` that uses struct name as a root tag name.
561    ///
562    /// Note, that attempt to serialize a non-struct (including unit structs
563    /// and newtype structs) will end up to an error. Use `with_root` to create
564    /// serializer with explicitly defined root element name
565    pub fn new(writer: &'w mut W) -> Self {
566        Self {
567            ser: ContentSerializer {
568                writer,
569                level: QuoteLevel::Partial,
570                indent: Indent::None,
571                write_indent: false,
572                text_format: TextFormat::Text,
573                allow_primitive: true,
574                expand_empty_elements: false,
575            },
576            root_tag: None,
577        }
578    }
579
580    /// Creates a new `Serializer` that uses specified root tag name. `name` should
581    /// be valid [XML name], otherwise error is returned.
582    ///
583    /// # Examples
584    ///
585    /// When serializing a primitive type, only its representation will be written:
586    ///
587    /// ```
588    /// # use pretty_assertions::assert_eq;
589    /// # use serde::Serialize;
590    /// # use quick_xml::se::Serializer;
591    ///
592    /// let mut buffer = String::new();
593    /// let ser = Serializer::with_root(&mut buffer, Some("root")).unwrap();
594    ///
595    /// "node".serialize(ser).unwrap();
596    /// assert_eq!(buffer, "<root>node</root>");
597    /// ```
598    ///
599    /// When serializing a struct, newtype struct, unit struct or tuple `root_tag`
600    /// is used as tag name of root(s) element(s):
601    ///
602    /// ```
603    /// # use pretty_assertions::assert_eq;
604    /// # use serde::Serialize;
605    /// # use quick_xml::se::Serializer;
606    ///
607    /// #[derive(Debug, PartialEq, Serialize)]
608    /// struct Struct {
609    ///     question: String,
610    ///     answer: u32,
611    /// }
612    ///
613    /// let mut buffer = String::new();
614    /// let ser = Serializer::with_root(&mut buffer, Some("root")).unwrap();
615    ///
616    /// let data = Struct {
617    ///     question: "The Ultimate Question of Life, the Universe, and Everything".into(),
618    ///     answer: 42,
619    /// };
620    ///
621    /// data.serialize(ser).unwrap();
622    /// assert_eq!(
623    ///     buffer,
624    ///     "<root>\
625    ///         <question>The Ultimate Question of Life, the Universe, and Everything</question>\
626    ///         <answer>42</answer>\
627    ///      </root>"
628    /// );
629    /// ```
630    ///
631    /// [XML name]: https://www.w3.org/TR/xml11/#NT-Name
632    pub fn with_root(writer: &'w mut W, root_tag: Option<&'r str>) -> Result<Self, SeError> {
633        Ok(Self {
634            ser: ContentSerializer {
635                writer,
636                level: QuoteLevel::Partial,
637                indent: Indent::None,
638                write_indent: false,
639                text_format: TextFormat::Text,
640                allow_primitive: true,
641                expand_empty_elements: false,
642            },
643            root_tag: root_tag.map(XmlName::try_from).transpose()?,
644        })
645    }
646
647    /// Enable or disable expansion of empty elements. Defaults to `false`.
648    ///
649    /// # Examples
650    ///
651    /// ```
652    /// # use pretty_assertions::assert_eq;
653    /// # use serde::Serialize;
654    /// # use quick_xml::se::Serializer;
655    ///
656    /// #[derive(Debug, PartialEq, Serialize)]
657    /// struct Struct {
658    ///     question: Option<String>,
659    /// }
660    ///
661    /// let mut buffer = String::new();
662    /// let mut ser = Serializer::new(&mut buffer);
663    /// ser.expand_empty_elements(true);
664    ///
665    /// let data = Struct {
666    ///   question: None,
667    /// };
668    ///
669    /// data.serialize(ser).unwrap();
670    /// assert_eq!(
671    ///     buffer,
672    ///     "<Struct><question></question></Struct>"
673    /// );
674    /// ```
675    pub fn expand_empty_elements(&mut self, expand: bool) -> &mut Self {
676        self.ser.expand_empty_elements = expand;
677        self
678    }
679
680    /// Set the text format used for serializing text content.
681    ///
682    /// - [`TextFormat::Text`]: Regular XML escaping (default)
683    /// - [`TextFormat::CData`]: CDATA sections for text content
684    ///
685    /// # Examples
686    ///
687    /// ```
688    /// # use pretty_assertions::assert_eq;
689    /// # use serde::Serialize;
690    /// # use quick_xml::se::{Serializer, TextFormat};
691    ///
692    /// #[derive(Debug, PartialEq, Serialize)]
693    /// struct Document {
694    ///     #[serde(rename = "$text")]
695    ///     content: String,
696    /// }
697    ///
698    /// let mut buffer = String::new();
699    /// let mut ser = Serializer::with_root(&mut buffer, Some("doc")).unwrap();
700    /// ser.text_format(TextFormat::CData);
701    ///
702    /// let data = Document {
703    ///     content: "Content with <markup> & entities".to_string(),
704    /// };
705    ///
706    /// data.serialize(ser).unwrap();
707    /// assert_eq!(buffer, "<doc><![CDATA[Content with <markup> & entities]]></doc>");
708    /// ```
709    pub fn text_format(&mut self, format: TextFormat) -> &mut Self {
710        self.ser.text_format = format;
711        self
712    }
713
714    /// Configure indent for a serializer
715    pub fn indent(&mut self, indent_char: char, indent_size: usize) -> &mut Self {
716        self.ser.indent = Indent::Owned(Indentation::new(indent_char as u8, indent_size));
717        self
718    }
719
720    /// Set the level of quoting used when writing texts
721    ///
722    /// Default: [`QuoteLevel::Minimal`]
723    pub fn set_quote_level(&mut self, level: QuoteLevel) -> &mut Self {
724        self.ser.level = level;
725        self
726    }
727
728    /// Set the indent object for a serializer
729    pub(crate) fn set_indent(&mut self, indent: Indent<'r>) -> &mut Self {
730        self.ser.indent = indent;
731        self
732    }
733
734    /// Creates actual serializer or returns an error if root tag is not defined.
735    /// In that case `err` contains the name of type that cannot be serialized.
736    fn ser(self, err: &str) -> Result<ElementSerializer<'w, 'r, W>, SeError> {
737        if let Some(key) = self.root_tag {
738            Ok(ElementSerializer { ser: self.ser, key })
739        } else {
740            Err(SeError::Unsupported(
741                format!("cannot serialize {} without defined root tag", err).into(),
742            ))
743        }
744    }
745
746    /// Creates actual serializer using root tag or a specified `key` if root tag
747    /// is not defined. Returns an error if root tag is not defined and a `key`
748    /// does not conform [XML rules](XmlName::try_from) for names.
749    fn ser_name(self, key: &'static str) -> Result<ElementSerializer<'w, 'r, W>, SeError> {
750        Ok(ElementSerializer {
751            ser: self.ser,
752            key: match self.root_tag {
753                Some(key) => key,
754                None => XmlName::try_from(key)?,
755            },
756        })
757    }
758}
759
760impl<'w, 'r, W: Write> ser::Serializer for Serializer<'w, 'r, W> {
761    type Ok = WriteResult;
762    type Error = SeError;
763
764    type SerializeSeq = ElementSerializer<'w, 'r, W>;
765    type SerializeTuple = ElementSerializer<'w, 'r, W>;
766    type SerializeTupleStruct = ElementSerializer<'w, 'r, W>;
767    type SerializeTupleVariant = Tuple<'w, 'r, W>;
768    type SerializeMap = Map<'w, 'r, W>;
769    type SerializeStruct = Struct<'w, 'r, W>;
770    type SerializeStructVariant = Struct<'w, 'r, W>;
771
772    forward!(serialize_bool(bool));
773
774    forward!(serialize_i8(i8));
775    forward!(serialize_i16(i16));
776    forward!(serialize_i32(i32));
777    forward!(serialize_i64(i64));
778
779    forward!(serialize_u8(u8));
780    forward!(serialize_u16(u16));
781    forward!(serialize_u32(u32));
782    forward!(serialize_u64(u64));
783
784    serde_if_integer128! {
785        forward!(serialize_i128(i128));
786        forward!(serialize_u128(u128));
787    }
788
789    forward!(serialize_f32(f32));
790    forward!(serialize_f64(f64));
791
792    forward!(serialize_char(char));
793    forward!(serialize_str(&str));
794    forward!(serialize_bytes(&[u8]));
795
796    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
797        // Do not write indent after `Option` field with `None` value, because
798        // this can be `Option<String>`. Unfortunately, we do not known what the
799        // type the option contains, so have no chance to adapt our behavior to it.
800        // The safe variant is not to write indent
801        Ok(WriteResult::SensitiveNothing)
802    }
803
804    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
805        value.serialize(self)
806    }
807
808    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
809        self.ser("`()`")?.serialize_unit()
810    }
811
812    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
813        self.ser_name(name)?.serialize_unit_struct(name)
814    }
815
816    fn serialize_unit_variant(
817        self,
818        name: &'static str,
819        _variant_index: u32,
820        variant: &'static str,
821    ) -> Result<Self::Ok, Self::Error> {
822        if variant == TEXT_KEY {
823            // We should write some text but we don't known what text to write
824            Err(SeError::Unsupported(
825                format!(
826                    "cannot serialize enum unit variant `{}::$text` as text content value",
827                    name
828                )
829                .into(),
830            ))
831        } else {
832            let name = XmlName::try_from(variant)?;
833            self.ser.write_empty(name)
834        }
835    }
836
837    fn serialize_newtype_struct<T: ?Sized + Serialize>(
838        self,
839        name: &'static str,
840        value: &T,
841    ) -> Result<Self::Ok, Self::Error> {
842        self.ser_name(name)?.serialize_newtype_struct(name, value)
843    }
844
845    fn serialize_newtype_variant<T: ?Sized + Serialize>(
846        self,
847        _name: &'static str,
848        _variant_index: u32,
849        variant: &'static str,
850        value: &T,
851    ) -> Result<Self::Ok, Self::Error> {
852        if variant == TEXT_KEY {
853            value.serialize(self.ser.into_simple_type_serializer()?)?;
854            // Do not write indent after `$text` variant because it may be interpreted as
855            // part of content when deserialize
856            Ok(WriteResult::SensitiveText)
857        } else {
858            let ser = ElementSerializer {
859                ser: self.ser,
860                key: XmlName::try_from(variant)?,
861            };
862            value.serialize(ser)
863        }
864    }
865
866    fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
867        self.ser("sequence")?.serialize_seq(len)
868    }
869
870    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
871        self.ser("unnamed tuple")?.serialize_tuple(len)
872    }
873
874    fn serialize_tuple_struct(
875        self,
876        name: &'static str,
877        len: usize,
878    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
879        self.ser_name(name)?.serialize_tuple_struct(name, len)
880    }
881
882    fn serialize_tuple_variant(
883        self,
884        name: &'static str,
885        _variant_index: u32,
886        variant: &'static str,
887        len: usize,
888    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
889        if variant == TEXT_KEY {
890            self.ser
891                .into_simple_type_serializer()?
892                .serialize_tuple_struct(name, len)
893                .map(Tuple::Text)
894        } else {
895            let ser = ElementSerializer {
896                ser: self.ser,
897                key: XmlName::try_from(variant)?,
898            };
899            ser.serialize_tuple_struct(name, len).map(Tuple::Element)
900        }
901    }
902
903    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
904        self.ser("map")?.serialize_map(len)
905    }
906
907    fn serialize_struct(
908        self,
909        name: &'static str,
910        len: usize,
911    ) -> Result<Self::SerializeStruct, Self::Error> {
912        self.ser_name(name)?.serialize_struct(name, len)
913    }
914
915    fn serialize_struct_variant(
916        self,
917        name: &'static str,
918        _variant_index: u32,
919        variant: &'static str,
920        len: usize,
921    ) -> Result<Self::SerializeStructVariant, Self::Error> {
922        if variant == TEXT_KEY {
923            Err(SeError::Unsupported(
924                format!(
925                    "cannot serialize enum struct variant `{}::$text` as text content value",
926                    name
927                )
928                .into(),
929            ))
930        } else {
931            let ser = ElementSerializer {
932                ser: self.ser,
933                key: XmlName::try_from(variant)?,
934            };
935            ser.serialize_struct(name, len)
936        }
937    }
938}
939
940#[cfg(test)]
941mod quote_level {
942    use super::*;
943    use pretty_assertions::assert_eq;
944    use serde::Serialize;
945
946    #[derive(Debug, PartialEq, Serialize)]
947    struct Element(&'static str);
948
949    #[derive(Debug, PartialEq, Serialize)]
950    struct Example {
951        #[serde(rename = "@attribute")]
952        attribute: &'static str,
953        element: Element,
954    }
955
956    #[test]
957    fn default_() {
958        let example = Example {
959            attribute: "special chars: &, <, >, \", '",
960            element: Element("special chars: &, <, >, \", '"),
961        };
962
963        let mut buffer = String::new();
964        let ser = Serializer::new(&mut buffer);
965
966        example.serialize(ser).unwrap();
967        assert_eq!(
968            buffer,
969            "<Example attribute=\"special chars: &amp;, &lt;, &gt;, &quot;, '\">\
970                <element>special chars: &amp;, &lt;, &gt;, \", '</element>\
971            </Example>"
972        );
973    }
974
975    #[test]
976    fn minimal() {
977        let example = Example {
978            attribute: "special chars: &, <, >, \", '",
979            element: Element("special chars: &, <, >, \", '"),
980        };
981
982        let mut buffer = String::new();
983        let mut ser = Serializer::new(&mut buffer);
984        ser.set_quote_level(QuoteLevel::Minimal);
985
986        example.serialize(ser).unwrap();
987        assert_eq!(
988            buffer,
989            "<Example attribute=\"special chars: &amp;, &lt;, >, &quot;, '\">\
990                <element>special chars: &amp;, &lt;, >, \", '</element>\
991            </Example>"
992        );
993    }
994
995    #[test]
996    fn partial() {
997        let example = Example {
998            attribute: "special chars: &, <, >, \", '",
999            element: Element("special chars: &, <, >, \", '"),
1000        };
1001
1002        let mut buffer = String::new();
1003        let mut ser = Serializer::new(&mut buffer);
1004        ser.set_quote_level(QuoteLevel::Partial);
1005
1006        example.serialize(ser).unwrap();
1007        assert_eq!(
1008            buffer,
1009            "<Example attribute=\"special chars: &amp;, &lt;, &gt;, &quot;, '\">\
1010                <element>special chars: &amp;, &lt;, &gt;, \", '</element>\
1011            </Example>"
1012        );
1013    }
1014
1015    #[test]
1016    fn full() {
1017        let example = Example {
1018            attribute: "special chars: &, <, >, \", '",
1019            element: Element("special chars: &, <, >, \", '"),
1020        };
1021
1022        let mut buffer = String::new();
1023        let mut ser = Serializer::new(&mut buffer);
1024        ser.set_quote_level(QuoteLevel::Full);
1025
1026        example.serialize(ser).unwrap();
1027        assert_eq!(
1028            buffer,
1029            "<Example attribute=\"special chars: &amp;, &lt;, &gt;, &quot;, &apos;\">\
1030                <element>special chars: &amp;, &lt;, &gt;, &quot;, &apos;</element>\
1031            </Example>"
1032        );
1033    }
1034}