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 /// `<` | `<`
347 /// `>` | `>`
348 /// `&` | `&`
349 /// `"` | `"`
350 /// `'` | `'`
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 /// `<` | `<`
362 /// `>` | `>`
363 /// `&` | `&`
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 /// `<` | `<`
375 /// `&` | `&`
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: &, <, >, ", '\">\
970 <element>special chars: &, <, >, \", '</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: &, <, >, ", '\">\
990 <element>special chars: &, <, >, \", '</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: &, <, >, ", '\">\
1010 <element>special chars: &, <, >, \", '</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: &, <, >, ", '\">\
1030 <element>special chars: &, <, >, ", '</element>\
1031 </Example>"
1032 );
1033 }
1034}