Skip to main content

serde_xml/
ser.rs

1//! Serde serializer for XML.
2//!
3//! This module provides a full-featured Serde serializer that converts
4//! Rust data structures into XML documents.
5//!
6//! ## Attribute Serialization
7//!
8//! Fields can be serialized as XML attributes by using the `@` prefix:
9//!
10//! ```rust
11//! use serde::Serialize;
12//! use serde_xml::to_string;
13//!
14//! #[derive(Serialize)]
15//! struct Element {
16//!     #[serde(rename = "@id")]
17//!     id: String,
18//!     #[serde(rename = "@class")]
19//!     class: String,
20//!     content: String,
21//! }
22//!
23//! let elem = Element {
24//!     id: "main".to_string(),
25//!     class: "container".to_string(),
26//!     content: "Hello".to_string(),
27//! };
28//!
29//! let xml = to_string(&elem).unwrap();
30//! // Output: <Element id="main" class="container"><content>Hello</content></Element>
31//! ```
32
33use crate::error::{Error, Result};
34use crate::escape::escape;
35use serde::ser::{self, Serialize};
36use std::io::Write;
37use std::sync::Arc;
38
39/// Serializes a value to an XML string.
40///
41/// # Maps
42///
43/// Map keys are used verbatim as element names, so they must be valid XML
44/// names for the output to be strictly valid XML. Keys such as `1` or
45/// strings containing spaces produce structurally balanced but not
46/// strictly valid documents. Keys containing markup characters (`<`, `>`,
47/// `&`, quotes, or whitespace) are written verbatim into the tag names and
48/// will break the document structure — map keys must be trusted or
49/// validated by the caller.
50///
51/// # Example
52///
53/// ```
54/// use serde::Serialize;
55/// use serde_xml::to_string;
56///
57/// #[derive(Serialize)]
58/// struct Person {
59///     name: String,
60///     age: u32,
61/// }
62///
63/// let person = Person {
64///     name: "Alice".to_string(),
65///     age: 30,
66/// };
67///
68/// let xml = to_string(&person).unwrap();
69/// assert!(xml.contains("<name>Alice</name>"));
70/// ```
71pub fn to_string<T>(value: &T) -> Result<String>
72where
73    T: Serialize + ?Sized,
74{
75    let mut serializer = Serializer::new();
76    value.serialize(&mut serializer)?;
77    Ok(serializer.into_string())
78}
79
80/// Serializes a value to an XML string with a root element name.
81pub fn to_string_with_root<T>(value: &T, root: &str) -> Result<String>
82where
83    T: Serialize + ?Sized,
84{
85    let mut serializer = Serializer::with_root(root);
86    value.serialize(&mut serializer)?;
87    Ok(serializer.into_string())
88}
89
90/// Serializes a value to XML bytes.
91pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
92where
93    T: Serialize + ?Sized,
94{
95    Ok(to_string(value)?.into_bytes())
96}
97
98/// Serializes a value to a writer.
99pub fn to_writer<W, T>(writer: W, value: &T) -> Result<()>
100where
101    W: Write,
102    T: Serialize + ?Sized,
103{
104    let xml = to_string(value)?;
105    let mut writer = writer;
106    writer.write_all(xml.as_bytes())?;
107    Ok(())
108}
109
110/// An element name held without a per-name heap allocation:
111/// struct/variant/field names are `&'static str`, everything else
112/// (map keys, configured roots) lives in an `Arc<str>` that can be
113/// shared. Cloning is cheap in both arms.
114#[derive(Clone)]
115enum TagName {
116    Static(&'static str),
117    Shared(Arc<str>),
118}
119
120impl TagName {
121    fn as_str(&self) -> &str {
122        match self {
123            TagName::Static(s) => s,
124            TagName::Shared(s) => s,
125        }
126    }
127}
128
129impl From<&'static str> for TagName {
130    fn from(s: &'static str) -> Self {
131        TagName::Static(s)
132    }
133}
134
135/// The XML serializer.
136pub struct Serializer {
137    output: String,
138    /// Root element name (for when we don't have type name info).
139    root: Option<Arc<str>>,
140    /// Current element name (set by newtype structs).
141    current_element: Option<&'static str>,
142    /// Stack of element names for nested structures.
143    element_stack: Vec<TagName>,
144    /// Whether we're serializing a map key.
145    is_key: bool,
146    /// Pending name for the next element: a struct field or variant name
147    /// (`Static`, never allocates) or a rendered map key (`Shared`).
148    current_key: Option<TagName>,
149    /// Whether to include XML declaration.
150    include_declaration: bool,
151    /// Indentation level.
152    indent_level: usize,
153    /// Indentation string.
154    indent_str: Option<String>,
155}
156
157impl Serializer {
158    /// Creates a new serializer.
159    pub fn new() -> Self {
160        Self {
161            output: String::new(),
162            root: None,
163            current_element: None,
164            element_stack: Vec::new(),
165            is_key: false,
166            current_key: None,
167            include_declaration: false,
168            indent_level: 0,
169            indent_str: None,
170        }
171    }
172
173    /// Creates a new serializer with a root element name.
174    pub fn with_root(root: &str) -> Self {
175        Self {
176            root: Some(Arc::from(root)),
177            ..Self::new()
178        }
179    }
180
181    /// Enables pretty-printing with the given indentation.
182    pub fn with_indent(mut self, indent: &str) -> Self {
183        self.indent_str = Some(indent.to_string());
184        self
185    }
186
187    /// Includes XML declaration in the output.
188    pub fn with_declaration(mut self) -> Self {
189        self.include_declaration = true;
190        self
191    }
192
193    /// Returns the serialized XML string.
194    ///
195    /// Note: after a serialization error the serializer's buffer may hold
196    /// partial output; the serializer is single-use and must not be reused
197    /// after an `Err`.
198    pub fn into_string(self) -> String {
199        if self.include_declaration {
200            let mut result = String::with_capacity(self.output.len() + 40);
201            result.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
202            result.push_str(&self.output);
203            result
204        } else {
205            self.output
206        }
207    }
208
209    /// Writes an opening tag.
210    fn write_start_tag(&mut self, name: impl Into<TagName>) {
211        let name = name.into();
212        self.write_indent();
213        self.output.push('<');
214        self.output.push_str(name.as_str());
215        self.output.push('>');
216        self.element_stack.push(name);
217        self.indent_level += 1;
218    }
219
220    /// Writes an opening tag with attributes.
221    fn write_start_tag_with_attrs(&mut self, name: impl Into<TagName>, attrs: &[(String, String)]) {
222        let name = name.into();
223        self.write_indent();
224        self.output.push('<');
225        self.output.push_str(name.as_str());
226        for (attr_name, attr_value) in attrs {
227            self.output.push(' ');
228            self.output.push_str(attr_name);
229            self.output.push_str("=\"");
230            self.output.push_str(&escape(attr_value));
231            self.output.push('"');
232        }
233        self.output.push('>');
234        self.element_stack.push(name);
235        self.indent_level += 1;
236    }
237
238    /// Rolls back a start tag whose element turned out to produce no
239    /// content: truncates the output back to `rollback_to`, pops the
240    /// element stack, and decrements the indent level. This must undo
241    /// exactly what `write_start_tag_with_attrs` does.
242    fn undo_start_tag(&mut self, rollback_to: usize) {
243        self.output.truncate(rollback_to);
244        self.element_stack.pop();
245        self.indent_level = self.indent_level.saturating_sub(1);
246    }
247
248    /// Writes a closing tag.
249    fn write_end_tag(&mut self) {
250        self.indent_level = self.indent_level.saturating_sub(1);
251
252        if let Some(name) = self.element_stack.pop() {
253            self.write_indent();
254            self.output.push_str("</");
255            self.output.push_str(name.as_str());
256            self.output.push('>');
257        }
258    }
259
260    /// Writes an empty element.
261    fn write_empty_element(&mut self, name: &str) {
262        self.write_indent();
263        self.output.push('<');
264        self.output.push_str(name);
265        self.output.push_str("/>");
266    }
267
268    /// Writes an empty element with attributes.
269    fn write_empty_element_with_attrs(&mut self, name: &str, attrs: &[(String, String)]) {
270        self.write_indent();
271        self.output.push('<');
272        self.output.push_str(name);
273        for (attr_name, attr_value) in attrs {
274            self.output.push(' ');
275            self.output.push_str(attr_name);
276            self.output.push_str("=\"");
277            self.output.push_str(&escape(attr_value));
278            self.output.push('"');
279        }
280        self.output.push_str("/>");
281    }
282
283    /// Writes a complete element with text content.
284    fn write_element(&mut self, name: &str, content: &str) {
285        self.write_indent();
286        self.output.push('<');
287        self.output.push_str(name);
288        self.output.push('>');
289        self.output.push_str(&escape(content));
290        self.output.push_str("</");
291        self.output.push_str(name);
292        self.output.push('>');
293    }
294
295    /// Writes text content.
296    fn write_text(&mut self, content: &str) {
297        self.output.push_str(&escape(content));
298    }
299
300    /// Writes indentation if configured.
301    fn write_indent(&mut self) {
302        if let Some(ref indent) = self.indent_str {
303            if !self.output.is_empty() && !self.output.ends_with('\n') {
304                self.output.push('\n');
305            }
306            for _ in 0..self.indent_level {
307                self.output.push_str(indent);
308            }
309        }
310    }
311
312    /// Takes the pending element name: an explicit key, the current
313    /// newtype-struct name, the configured root, or the fallback.
314    fn take_element_name(&mut self, fallback: &'static str) -> TagName {
315        self.current_key
316            .take()
317            .or_else(|| self.current_element.map(TagName::Static))
318            .or_else(|| self.root.clone().map(TagName::Shared))
319            .unwrap_or(TagName::Static(fallback))
320    }
321
322    /// Emits scalar text in the current context: captured as a map key,
323    /// wrapped in a `<key>text</key>` element when in field position, or
324    /// written as bare text content.
325    fn emit_scalar(&mut self, text: &str) {
326        if self.is_key {
327            self.current_key = Some(TagName::Shared(Arc::from(text)));
328            self.is_key = false;
329        } else if let Some(key) = self.current_key.take() {
330            self.write_element(key.as_str(), text);
331        } else {
332            self.write_text(text);
333        }
334    }
335
336    /// In field position, wraps a variant in the field element so the
337    /// field name survives the round trip:
338    /// `<status><Count>42</Count></status>`.
339    ///
340    /// Returns whether a wrapper tag was opened; the caller must close it
341    /// with a matching `write_end_tag` when it returns `true`.
342    fn open_field_wrapper(&mut self) -> bool {
343        match self.current_key.take() {
344            Some(key) => {
345                self.write_start_tag(key);
346                true
347            }
348            None => false,
349        }
350    }
351}
352
353impl Default for Serializer {
354    fn default() -> Self {
355        Self::new()
356    }
357}
358
359impl<'a> ser::Serializer for &'a mut Serializer {
360    type Ok = ();
361    type Error = Error;
362
363    type SerializeSeq = SeqSerializer<'a>;
364    type SerializeTuple = SeqSerializer<'a>;
365    type SerializeTupleStruct = SeqSerializer<'a>;
366    type SerializeTupleVariant = SeqSerializer<'a>;
367    type SerializeMap = MapSerializer<'a>;
368    type SerializeStruct = StructSerializer<'a>;
369    type SerializeStructVariant = StructSerializer<'a>;
370
371    fn serialize_bool(self, v: bool) -> Result<()> {
372        self.emit_scalar(if v { "true" } else { "false" });
373        Ok(())
374    }
375
376    fn serialize_i8(self, v: i8) -> Result<()> {
377        self.serialize_i64(v as i64)
378    }
379
380    fn serialize_i16(self, v: i16) -> Result<()> {
381        self.serialize_i64(v as i64)
382    }
383
384    fn serialize_i32(self, v: i32) -> Result<()> {
385        self.serialize_i64(v as i64)
386    }
387
388    fn serialize_i64(self, v: i64) -> Result<()> {
389        let mut buffer = itoa::Buffer::new();
390        self.emit_scalar(buffer.format(v));
391        Ok(())
392    }
393
394    fn serialize_u8(self, v: u8) -> Result<()> {
395        self.serialize_u64(v as u64)
396    }
397
398    fn serialize_u16(self, v: u16) -> Result<()> {
399        self.serialize_u64(v as u64)
400    }
401
402    fn serialize_u32(self, v: u32) -> Result<()> {
403        self.serialize_u64(v as u64)
404    }
405
406    fn serialize_u64(self, v: u64) -> Result<()> {
407        let mut buffer = itoa::Buffer::new();
408        self.emit_scalar(buffer.format(v));
409        Ok(())
410    }
411
412    fn serialize_f32(self, v: f32) -> Result<()> {
413        self.serialize_f64(v as f64)
414    }
415
416    fn serialize_f64(self, v: f64) -> Result<()> {
417        let mut buffer = ryu::Buffer::new();
418        self.emit_scalar(buffer.format(v));
419        Ok(())
420    }
421
422    fn serialize_char(self, v: char) -> Result<()> {
423        let mut buf = [0u8; 4];
424        self.emit_scalar(v.encode_utf8(&mut buf));
425        Ok(())
426    }
427
428    fn serialize_str(self, v: &str) -> Result<()> {
429        self.emit_scalar(v);
430        Ok(())
431    }
432
433    fn serialize_bytes(self, v: &[u8]) -> Result<()> {
434        // Hex encode bytes (lowercase)
435        const HEX: &[u8; 16] = b"0123456789abcdef";
436        let mut encoded = String::with_capacity(v.len() * 2);
437        for &byte in v {
438            encoded.push(HEX[(byte >> 4) as usize] as char);
439            encoded.push(HEX[(byte & 0x0f) as usize] as char);
440        }
441        self.emit_scalar(&encoded);
442        Ok(())
443    }
444
445    fn serialize_none(self) -> Result<()> {
446        // Don't output anything for None
447        self.current_key = None;
448        Ok(())
449    }
450
451    fn serialize_some<T>(self, value: &T) -> Result<()>
452    where
453        T: Serialize + ?Sized,
454    {
455        value.serialize(self)
456    }
457
458    fn serialize_unit(self) -> Result<()> {
459        if let Some(key) = self.current_key.take() {
460            self.write_empty_element(key.as_str());
461        }
462        Ok(())
463    }
464
465    fn serialize_unit_struct(self, name: &'static str) -> Result<()> {
466        let elem_name = self.take_element_name(name);
467        self.write_empty_element(elem_name.as_str());
468        Ok(())
469    }
470
471    fn serialize_unit_variant(
472        self,
473        _name: &'static str,
474        _variant_index: u32,
475        variant: &'static str,
476    ) -> Result<()> {
477        if let Some(key) = self.current_key.take() {
478            self.write_element(key.as_str(), variant);
479        } else {
480            self.write_empty_element(variant);
481        }
482        Ok(())
483    }
484
485    fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<()>
486    where
487        T: Serialize + ?Sized,
488    {
489        self.current_element = Some(name);
490        value.serialize(self)
491    }
492
493    fn serialize_newtype_variant<T>(
494        self,
495        _name: &'static str,
496        _variant_index: u32,
497        variant: &'static str,
498        value: &T,
499    ) -> Result<()>
500    where
501        T: Serialize + ?Sized,
502    {
503        let wrapped = self.open_field_wrapper();
504        self.write_start_tag(variant);
505        value.serialize(&mut *self)?;
506        self.write_end_tag();
507        if wrapped {
508            self.write_end_tag();
509        }
510        Ok(())
511    }
512
513    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
514        let element_name = self.current_key.take().unwrap_or(TagName::Static("item"));
515        Ok(SeqSerializer {
516            ser: self,
517            element_name,
518            wrapped: false,
519        })
520    }
521
522    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
523        self.serialize_seq(Some(len))
524    }
525
526    fn serialize_tuple_struct(
527        self,
528        name: &'static str,
529        _len: usize,
530    ) -> Result<Self::SerializeTupleStruct> {
531        self.write_start_tag(name);
532        Ok(SeqSerializer {
533            ser: self,
534            element_name: TagName::Static("item"),
535            wrapped: false,
536        })
537    }
538
539    fn serialize_tuple_variant(
540        self,
541        _name: &'static str,
542        _variant_index: u32,
543        variant: &'static str,
544        _len: usize,
545    ) -> Result<Self::SerializeTupleVariant> {
546        let wrapped = self.open_field_wrapper();
547        self.write_start_tag(variant);
548        Ok(SeqSerializer {
549            ser: self,
550            element_name: TagName::Static("item"),
551            wrapped,
552        })
553    }
554
555    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
556        let name = self.current_key.take()
557            .or_else(|| self.root.clone().map(TagName::Shared))
558            .unwrap_or(TagName::Static("map"));
559        self.write_start_tag(name);
560        Ok(MapSerializer { ser: self })
561    }
562
563    fn serialize_struct(self, name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
564        let elem_name = match self.current_key.take() {
565            Some(key) => key,
566            // Top-level struct (nothing written yet): prefer the configured root name.
567            None if self.output.is_empty() && self.element_stack.is_empty() => self
568                .root
569                .clone()
570                .map(TagName::Shared)
571                .unwrap_or(TagName::Static(name)),
572            None => TagName::Static(name),
573        };
574        // The start tag is written lazily by the first element field so that
575        // attributes declared before it end up on the tag without buffering.
576        Ok(StructSerializer {
577            ser: self,
578            elem_name: Some(elem_name),
579            attrs: Vec::new(),
580            attr_insert_pos: None,
581            text_content: None,
582            wrapped: false,
583        })
584    }
585
586    fn serialize_struct_variant(
587        self,
588        _name: &'static str,
589        _variant_index: u32,
590        variant: &'static str,
591        _len: usize,
592    ) -> Result<Self::SerializeStructVariant> {
593        let wrapped = self.open_field_wrapper();
594        Ok(StructSerializer {
595            ser: self,
596            elem_name: Some(TagName::Static(variant)),
597            attrs: Vec::new(),
598            attr_insert_pos: None,
599            text_content: None,
600            wrapped,
601        })
602    }
603}
604
605/// Simple serializer for attribute values (no XML escaping - escaping done at output).
606struct AttrValueSerializer {
607    output: String,
608}
609
610impl AttrValueSerializer {
611    fn new() -> Self {
612        Self { output: String::new() }
613    }
614
615    fn into_string(self) -> String {
616        self.output
617    }
618}
619
620impl ser::Serializer for &mut AttrValueSerializer {
621    type Ok = ();
622    type Error = Error;
623
624    type SerializeSeq = ser::Impossible<(), Error>;
625    type SerializeTuple = ser::Impossible<(), Error>;
626    type SerializeTupleStruct = ser::Impossible<(), Error>;
627    type SerializeTupleVariant = ser::Impossible<(), Error>;
628    type SerializeMap = ser::Impossible<(), Error>;
629    type SerializeStruct = ser::Impossible<(), Error>;
630    type SerializeStructVariant = ser::Impossible<(), Error>;
631
632    fn serialize_bool(self, v: bool) -> Result<()> {
633        self.output.push_str(if v { "true" } else { "false" });
634        Ok(())
635    }
636
637    fn serialize_i8(self, v: i8) -> Result<()> { self.serialize_i64(v as i64) }
638    fn serialize_i16(self, v: i16) -> Result<()> { self.serialize_i64(v as i64) }
639    fn serialize_i32(self, v: i32) -> Result<()> { self.serialize_i64(v as i64) }
640    fn serialize_i64(self, v: i64) -> Result<()> {
641        let mut buffer = itoa::Buffer::new();
642        self.output.push_str(buffer.format(v));
643        Ok(())
644    }
645
646    fn serialize_u8(self, v: u8) -> Result<()> { self.serialize_u64(v as u64) }
647    fn serialize_u16(self, v: u16) -> Result<()> { self.serialize_u64(v as u64) }
648    fn serialize_u32(self, v: u32) -> Result<()> { self.serialize_u64(v as u64) }
649    fn serialize_u64(self, v: u64) -> Result<()> {
650        let mut buffer = itoa::Buffer::new();
651        self.output.push_str(buffer.format(v));
652        Ok(())
653    }
654
655    fn serialize_f32(self, v: f32) -> Result<()> { self.serialize_f64(v as f64) }
656    fn serialize_f64(self, v: f64) -> Result<()> {
657        let mut buffer = ryu::Buffer::new();
658        self.output.push_str(buffer.format(v));
659        Ok(())
660    }
661
662    fn serialize_char(self, v: char) -> Result<()> {
663        self.output.push(v);
664        Ok(())
665    }
666
667    fn serialize_str(self, v: &str) -> Result<()> {
668        // No escaping here - escaping happens when writing the attribute
669        self.output.push_str(v);
670        Ok(())
671    }
672
673    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
674        Err(Error::unsupported("bytes in attribute"))
675    }
676
677    fn serialize_none(self) -> Result<()> { Ok(()) }
678    fn serialize_some<T: ?Sized + Serialize>(self, v: &T) -> Result<()> { v.serialize(self) }
679    fn serialize_unit(self) -> Result<()> { Ok(()) }
680    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { Ok(()) }
681    fn serialize_unit_variant(self, _name: &'static str, _idx: u32, variant: &'static str) -> Result<()> {
682        self.output.push_str(variant);
683        Ok(())
684    }
685    fn serialize_newtype_struct<T: ?Sized + Serialize>(self, _name: &'static str, v: &T) -> Result<()> {
686        v.serialize(self)
687    }
688    fn serialize_newtype_variant<T: ?Sized + Serialize>(self, _name: &'static str, _idx: u32, _variant: &'static str, v: &T) -> Result<()> {
689        v.serialize(self)
690    }
691
692    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
693        Err(Error::unsupported("sequence in attribute"))
694    }
695    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
696        Err(Error::unsupported("tuple in attribute"))
697    }
698    fn serialize_tuple_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeTupleStruct> {
699        Err(Error::unsupported("tuple struct in attribute"))
700    }
701    fn serialize_tuple_variant(self, _name: &'static str, _idx: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeTupleVariant> {
702        Err(Error::unsupported("tuple variant in attribute"))
703    }
704    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
705        Err(Error::unsupported("map in attribute"))
706    }
707    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
708        Err(Error::unsupported("struct in attribute"))
709    }
710    fn serialize_struct_variant(self, _name: &'static str, _idx: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeStructVariant> {
711        Err(Error::unsupported("struct variant in attribute"))
712    }
713}
714
715/// Sequence serializer.
716pub struct SeqSerializer<'a> {
717    ser: &'a mut Serializer,
718    element_name: TagName,
719    /// Whether a field wrapper element was opened and must be closed in
720    /// `end()` (tuple variants in field position).
721    wrapped: bool,
722}
723
724impl<'a> ser::SerializeSeq for SeqSerializer<'a> {
725    type Ok = ();
726    type Error = Error;
727
728    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
729    where
730        T: Serialize + ?Sized,
731    {
732        self.ser.current_key = Some(self.element_name.clone());
733        value.serialize(&mut *self.ser)
734    }
735
736    fn end(self) -> Result<()> {
737        Ok(())
738    }
739}
740
741impl<'a> ser::SerializeTuple for SeqSerializer<'a> {
742    type Ok = ();
743    type Error = Error;
744
745    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
746    where
747        T: Serialize + ?Sized,
748    {
749        ser::SerializeSeq::serialize_element(self, value)
750    }
751
752    fn end(self) -> Result<()> {
753        ser::SerializeSeq::end(self)
754    }
755}
756
757impl<'a> ser::SerializeTupleStruct for SeqSerializer<'a> {
758    type Ok = ();
759    type Error = Error;
760
761    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
762    where
763        T: Serialize + ?Sized,
764    {
765        self.ser.current_key = Some(self.element_name.clone());
766        value.serialize(&mut *self.ser)
767    }
768
769    fn end(self) -> Result<()> {
770        self.ser.write_end_tag();
771        Ok(())
772    }
773}
774
775impl<'a> ser::SerializeTupleVariant for SeqSerializer<'a> {
776    type Ok = ();
777    type Error = Error;
778
779    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
780    where
781        T: Serialize + ?Sized,
782    {
783        self.ser.current_key = Some(self.element_name.clone());
784        value.serialize(&mut *self.ser)
785    }
786
787    fn end(self) -> Result<()> {
788        self.ser.write_end_tag();
789        if self.wrapped {
790            self.ser.write_end_tag();
791        }
792        Ok(())
793    }
794}
795
796/// Map serializer.
797pub struct MapSerializer<'a> {
798    ser: &'a mut Serializer,
799}
800
801impl<'a> ser::SerializeMap for MapSerializer<'a> {
802    type Ok = ();
803    type Error = Error;
804
805    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
806    where
807        T: Serialize + ?Sized,
808    {
809        self.ser.is_key = true;
810        key.serialize(&mut *self.ser)
811    }
812
813    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
814    where
815        T: Serialize + ?Sized,
816    {
817        value.serialize(&mut *self.ser)
818    }
819
820    fn end(self) -> Result<()> {
821        self.ser.write_end_tag();
822        Ok(())
823    }
824}
825
826/// Struct serializer with attribute support.
827///
828/// Element fields stream directly into the shared output. The start tag is
829/// written when the first element field produces output, carrying the
830/// attributes collected up to that point; an attribute field that arrives
831/// *after* the start tag has been written is spliced into it in place.
832pub struct StructSerializer<'a> {
833    ser: &'a mut Serializer,
834    /// The element name; `Some` until the start tag has been written.
835    elem_name: Option<TagName>,
836    /// Attributes collected before the start tag is written.
837    attrs: Vec<(String, String)>,
838    /// Byte offset in `ser.output` just before the `>` of the written start
839    /// tag, where a late attribute must be inserted. `None` until the start
840    /// tag has been written.
841    attr_insert_pos: Option<usize>,
842    text_content: Option<String>,
843    /// Whether a field wrapper element was opened and must be closed in
844    /// `end()` (struct variants in field position).
845    wrapped: bool,
846}
847
848impl<'a> ser::SerializeStruct for StructSerializer<'a> {
849    type Ok = ();
850    type Error = Error;
851
852    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
853    where
854        T: Serialize + ?Sized,
855    {
856        // Check if this is an attribute (starts with @)
857        if let Some(attr_name) = key.strip_prefix('@') {
858            // Serialize value to string - use a special mode that doesn't escape
859            let mut attr_ser = AttrValueSerializer::new();
860            value.serialize(&mut attr_ser)?;
861            let attr_value = attr_ser.into_string();
862            if let Some(pos) = self.attr_insert_pos {
863                // The start tag is already in the output: splice the
864                // attribute into it (rare; costs one O(tail) move).
865                let mut rendered = String::with_capacity(attr_name.len() + attr_value.len() + 4);
866                rendered.push(' ');
867                rendered.push_str(attr_name);
868                rendered.push_str("=\"");
869                rendered.push_str(&escape(&attr_value));
870                rendered.push('"');
871                self.ser.output.insert_str(pos, &rendered);
872                self.attr_insert_pos = Some(pos + rendered.len());
873            } else {
874                self.attrs.push((attr_name.to_string(), attr_value));
875            }
876            return Ok(());
877        }
878
879        // Check if this is text content ($value or $text)
880        if key == "$value" || key == "$text" {
881            // Serialize directly into the (reused) text buffer instead of
882            // allocating a fresh one per field
883            let mut buf = self.text_content.take().unwrap_or_default();
884            buf.clear();
885            let mut text_ser = Serializer {
886                output: buf,
887                ..Serializer::new()
888            };
889            value.serialize(&mut text_ser)?;
890            self.text_content = Some(text_ser.output);
891            return Ok(());
892        }
893
894        // Regular field: stream directly into the shared output.
895        if let Some(name) = self.elem_name.take() {
896            // First element field: emit the start tag with the attributes
897            // collected so far and remember where late attributes go.
898            let rollback_to = self.ser.output.len();
899            self.ser.write_start_tag_with_attrs(name.clone(), &self.attrs);
900            let content_start = self.ser.output.len();
901            self.ser.current_key = Some(TagName::Static(key));
902            value.serialize(&mut *self.ser)?;
903            if self.ser.output.len() == content_start {
904                // The field produced no output (e.g. a `None`): undo the
905                // start tag so `end()` can still emit the empty or
906                // self-closing form.
907                self.ser.undo_start_tag(rollback_to);
908                self.ser.current_key = None;
909                self.elem_name = Some(name);
910            } else {
911                // `content_start - 1` is the `>` closing the start tag.
912                self.attr_insert_pos = Some(content_start - 1);
913            }
914        } else {
915            self.ser.current_key = Some(TagName::Static(key));
916            value.serialize(&mut *self.ser)?;
917        }
918        Ok(())
919    }
920
921    fn end(self) -> Result<()> {
922        match self.elem_name {
923            Some(name) => {
924                // No element children were written.
925                if let Some(text) = self.text_content {
926                    self.ser.write_start_tag_with_attrs(name, &self.attrs);
927                    self.ser.output.push_str(&text);
928                    self.ser.write_end_tag();
929                } else if self.attrs.is_empty() {
930                    // Empty element with no attributes
931                    self.ser.write_empty_element(name.as_str());
932                } else {
933                    // Element with only attributes
934                    self.ser.write_empty_element_with_attrs(name.as_str(), &self.attrs);
935                }
936            }
937            None => {
938                // Start tag and children already streamed; text content
939                // renders after the children, then the end tag closes.
940                if let Some(text) = self.text_content {
941                    self.ser.output.push_str(&text);
942                }
943                self.ser.write_end_tag();
944            }
945        }
946        if self.wrapped {
947            self.ser.write_end_tag();
948        }
949        Ok(())
950    }
951}
952
953impl<'a> ser::SerializeStructVariant for StructSerializer<'a> {
954    type Ok = ();
955    type Error = Error;
956
957    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
958    where
959        T: Serialize + ?Sized,
960    {
961        ser::SerializeStruct::serialize_field(self, key, value)
962    }
963
964    fn end(self) -> Result<()> {
965        ser::SerializeStruct::end(self)
966    }
967}
968
969#[cfg(test)]
970mod tests {
971    use super::*;
972    use serde::Serialize;
973
974    #[test]
975    fn test_serialize_simple_struct() {
976        #[derive(Serialize)]
977        struct Person {
978            name: String,
979            age: u32,
980        }
981
982        let person = Person {
983            name: "Alice".to_string(),
984            age: 30,
985        };
986
987        let xml = to_string(&person).unwrap();
988        assert!(xml.contains("<Person>"));
989        assert!(xml.contains("<name>Alice</name>"));
990        assert!(xml.contains("<age>30</age>"));
991        assert!(xml.contains("</Person>"));
992    }
993
994    #[test]
995    fn test_serialize_with_attributes() {
996        #[derive(Serialize)]
997        struct Element {
998            #[serde(rename = "@id")]
999            id: String,
1000            #[serde(rename = "@class")]
1001            class: String,
1002            content: String,
1003        }
1004
1005        let elem = Element {
1006            id: "main".to_string(),
1007            class: "container".to_string(),
1008            content: "Hello".to_string(),
1009        };
1010
1011        let xml = to_string(&elem).unwrap();
1012        assert!(xml.contains(r#"id="main""#));
1013        assert!(xml.contains(r#"class="container""#));
1014        assert!(xml.contains("<content>Hello</content>"));
1015    }
1016
1017    #[test]
1018    fn test_serialize_attributes_only() {
1019        #[derive(Serialize)]
1020        struct EmptyElement {
1021            #[serde(rename = "@id")]
1022            id: String,
1023            #[serde(rename = "@disabled")]
1024            disabled: bool,
1025        }
1026
1027        let elem = EmptyElement {
1028            id: "btn".to_string(),
1029            disabled: true,
1030        };
1031
1032        let xml = to_string(&elem).unwrap();
1033        assert!(xml.contains(r#"id="btn""#));
1034        assert!(xml.contains(r#"disabled="true""#));
1035        assert!(xml.contains("/>") || xml.contains("</EmptyElement>"));
1036    }
1037
1038    #[test]
1039    fn test_serialize_text_content() {
1040        #[derive(Serialize)]
1041        struct TextElement {
1042            #[serde(rename = "@id")]
1043            id: String,
1044            #[serde(rename = "$value")]
1045            text: String,
1046        }
1047
1048        let elem = TextElement {
1049            id: "para".to_string(),
1050            text: "Hello World".to_string(),
1051        };
1052
1053        let xml = to_string(&elem).unwrap();
1054        assert!(xml.contains(r#"id="para""#));
1055        assert!(xml.contains("Hello World"));
1056    }
1057
1058    #[test]
1059    fn test_serialize_nested_struct() {
1060        #[derive(Serialize)]
1061        struct Address {
1062            city: String,
1063            country: String,
1064        }
1065
1066        #[derive(Serialize)]
1067        struct Person {
1068            name: String,
1069            address: Address,
1070        }
1071
1072        let person = Person {
1073            name: "Bob".to_string(),
1074            address: Address {
1075                city: "New York".to_string(),
1076                country: "USA".to_string(),
1077            },
1078        };
1079
1080        let xml = to_string(&person).unwrap();
1081        assert!(xml.contains("<address>"));
1082        assert!(xml.contains("<city>New York</city>"));
1083        assert!(xml.contains("</address>"));
1084    }
1085
1086    #[test]
1087    fn test_serialize_optional() {
1088        #[derive(Serialize)]
1089        struct Config {
1090            name: String,
1091            value: Option<String>,
1092        }
1093
1094        let with_value = Config {
1095            name: "test".to_string(),
1096            value: Some("val".to_string()),
1097        };
1098        let xml = to_string(&with_value).unwrap();
1099        assert!(xml.contains("<value>val</value>"));
1100
1101        let without_value = Config {
1102            name: "test".to_string(),
1103            value: None,
1104        };
1105        let xml = to_string(&without_value).unwrap();
1106        assert!(!xml.contains("<value>"));
1107    }
1108
1109    #[test]
1110    fn test_serialize_vector() {
1111        #[derive(Serialize)]
1112        struct Items {
1113            items: Vec<String>,
1114        }
1115
1116        let items = Items {
1117            items: vec!["one".to_string(), "two".to_string(), "three".to_string()],
1118        };
1119
1120        let xml = to_string(&items).unwrap();
1121        assert!(xml.contains("<items>one</items>"));
1122        assert!(xml.contains("<items>two</items>"));
1123        assert!(xml.contains("<items>three</items>"));
1124    }
1125
1126    #[test]
1127    fn test_serialize_escaped_content() {
1128        #[derive(Serialize)]
1129        struct Data {
1130            content: String,
1131        }
1132
1133        let data = Data {
1134            content: "<hello> & \"world\"".to_string(),
1135        };
1136
1137        let xml = to_string(&data).unwrap();
1138        assert!(xml.contains("&lt;hello&gt;"));
1139        assert!(xml.contains("&amp;"));
1140        assert!(xml.contains("&quot;"));
1141    }
1142
1143    #[test]
1144    fn test_serialize_escaped_attribute() {
1145        #[derive(Serialize)]
1146        struct Element {
1147            #[serde(rename = "@title")]
1148            title: String,
1149        }
1150
1151        let elem = Element {
1152            title: "Hello \"World\" & <Friends>".to_string(),
1153        };
1154
1155        let xml = to_string(&elem).unwrap();
1156        assert!(xml.contains("&quot;"));
1157        assert!(xml.contains("&amp;"));
1158        assert!(xml.contains("&lt;"));
1159    }
1160
1161    #[test]
1162    fn test_serialize_bool() {
1163        #[derive(Serialize)]
1164        struct Flags {
1165            enabled: bool,
1166            active: bool,
1167        }
1168
1169        let flags = Flags {
1170            enabled: true,
1171            active: false,
1172        };
1173
1174        let xml = to_string(&flags).unwrap();
1175        assert!(xml.contains("<enabled>true</enabled>"));
1176        assert!(xml.contains("<active>false</active>"));
1177    }
1178
1179    #[test]
1180    fn test_serialize_numbers() {
1181        #[derive(Serialize)]
1182        struct Numbers {
1183            i: i32,
1184            u: u64,
1185            f: f64,
1186        }
1187
1188        let nums = Numbers {
1189            i: -42,
1190            u: 100,
1191            f: 1.234,
1192        };
1193
1194        let xml = to_string(&nums).unwrap();
1195        assert!(xml.contains("<i>-42</i>"));
1196        assert!(xml.contains("<u>100</u>"));
1197        assert!(xml.contains("<f>1.234</f>"));
1198    }
1199
1200    #[test]
1201    fn test_serialize_enum() {
1202        #[derive(Serialize)]
1203        enum Status {
1204            Active,
1205        }
1206
1207        #[derive(Serialize)]
1208        struct Item {
1209            status: Status,
1210        }
1211
1212        let item = Item {
1213            status: Status::Active,
1214        };
1215
1216        let xml = to_string(&item).unwrap();
1217        assert!(xml.contains("<status>Active</status>") || xml.contains("<Active/>"));
1218    }
1219
1220    #[test]
1221    fn test_serialize_unit_struct() {
1222        #[derive(Serialize)]
1223        struct Empty;
1224
1225        let xml = to_string(&Empty).unwrap();
1226        assert!(xml.contains("<Empty/>"));
1227    }
1228
1229    #[test]
1230    fn test_serialize_char() {
1231        #[derive(Serialize)]
1232        struct Data {
1233            c: char,
1234        }
1235
1236        let data = Data { c: 'A' };
1237        let xml = to_string(&data).unwrap();
1238        assert!(xml.contains("<c>A</c>"));
1239    }
1240
1241    #[test]
1242    fn test_to_vec() {
1243        #[derive(Serialize)]
1244        struct Data {
1245            value: String,
1246        }
1247
1248        let data = Data {
1249            value: "test".to_string(),
1250        };
1251
1252        let bytes = to_vec(&data).unwrap();
1253        let xml = String::from_utf8(bytes).unwrap();
1254        assert!(xml.contains("<value>test</value>"));
1255    }
1256
1257    #[test]
1258    fn test_to_writer() {
1259        #[derive(Serialize)]
1260        struct Data {
1261            value: String,
1262        }
1263
1264        let data = Data {
1265            value: "test".to_string(),
1266        };
1267
1268        let mut buffer = Vec::new();
1269        to_writer(&mut buffer, &data).unwrap();
1270        let xml = String::from_utf8(buffer).unwrap();
1271        assert!(xml.contains("<value>test</value>"));
1272    }
1273
1274    #[test]
1275    fn test_with_root() {
1276        #[derive(Serialize)]
1277        struct Data {
1278            value: String,
1279        }
1280
1281        let data = Data {
1282            value: "test".to_string(),
1283        };
1284
1285        let xml = to_string_with_root(&data, "root").unwrap();
1286        // The top-level struct serializes under the given root name
1287        assert_eq!(xml, "<root><value>test</value></root>");
1288    }
1289
1290    #[test]
1291    fn test_with_root_nested_uses_field_name() {
1292        #[derive(Serialize)]
1293        struct Inner {
1294            value: String,
1295        }
1296
1297        #[derive(Serialize)]
1298        struct Outer {
1299            inner: Inner,
1300        }
1301
1302        let outer = Outer {
1303            inner: Inner {
1304                value: "test".to_string(),
1305            },
1306        };
1307
1308        let xml = to_string_with_root(&outer, "root").unwrap();
1309        // Only the top-level element is renamed; nested structs keep their field name
1310        assert_eq!(xml, "<root><inner><value>test</value></inner></root>");
1311    }
1312
1313    #[test]
1314    fn test_complex_with_attributes() {
1315        #[derive(Serialize)]
1316        struct Item {
1317            #[serde(rename = "@id")]
1318            id: u32,
1319            #[serde(rename = "@class")]
1320            class: String,
1321            name: String,
1322            value: i32,
1323        }
1324
1325        #[derive(Serialize)]
1326        struct Container {
1327            #[serde(rename = "@version")]
1328            version: String,
1329            item: Vec<Item>,
1330        }
1331
1332        let container = Container {
1333            version: "1.0".to_string(),
1334            item: vec![
1335                Item {
1336                    id: 1,
1337                    class: "primary".to_string(),
1338                    name: "First".to_string(),
1339                    value: 100,
1340                },
1341                Item {
1342                    id: 2,
1343                    class: "secondary".to_string(),
1344                    name: "Second".to_string(),
1345                    value: 200,
1346                },
1347            ],
1348        };
1349
1350        let xml = to_string(&container).unwrap();
1351        assert!(xml.contains(r#"version="1.0""#));
1352        assert!(xml.contains(r#"id="1""#));
1353        assert!(xml.contains(r#"class="primary""#));
1354        assert!(xml.contains("<name>First</name>"));
1355    }
1356
1357    #[test]
1358    fn test_with_declaration() {
1359        #[derive(Serialize)]
1360        struct Data {
1361            value: String,
1362        }
1363
1364        let data = Data {
1365            value: "test".to_string(),
1366        };
1367
1368        let mut serializer = Serializer::new().with_declaration();
1369        data.serialize(&mut serializer).unwrap();
1370        let xml = serializer.into_string();
1371        assert!(xml.starts_with(r#"<?xml version="1.0" encoding="UTF-8"?>"#));
1372        assert!(xml.contains("<value>test</value>"));
1373    }
1374
1375    #[test]
1376    fn test_no_declaration_by_default() {
1377        #[derive(Serialize)]
1378        struct Data {
1379            value: String,
1380        }
1381
1382        let data = Data {
1383            value: "test".to_string(),
1384        };
1385
1386        let xml = to_string(&data).unwrap();
1387        assert!(!xml.contains("<?xml"));
1388    }
1389
1390    #[test]
1391    fn test_attribute_after_regular_field() {
1392        #[derive(Serialize)]
1393        struct Thing {
1394            name: String,
1395            #[serde(rename = "@id")]
1396            id: String,
1397        }
1398
1399        let thing = Thing {
1400            name: "widget".to_string(),
1401            id: "7".to_string(),
1402        };
1403
1404        let xml = to_string(&thing).unwrap();
1405        // The attribute belongs on the start tag even though it was declared
1406        // after a regular field
1407        assert_eq!(xml, r#"<Thing id="7"><name>widget</name></Thing>"#);
1408    }
1409
1410    #[test]
1411    fn test_serialize_map_numeric_keys() {
1412        use std::collections::BTreeMap;
1413
1414        let mut map = BTreeMap::new();
1415        map.insert(1u32, "one".to_string());
1416        map.insert(2u32, "two".to_string());
1417
1418        let xml = to_string(&map).unwrap();
1419        assert_eq!(xml, "<map><1>one</1><2>two</2></map>");
1420    }
1421
1422    #[test]
1423    fn test_serialize_newtype_variant() {
1424        #[derive(Serialize)]
1425        enum Value {
1426            Count(u32),
1427        }
1428
1429        let xml = to_string(&Value::Count(42)).unwrap();
1430        assert_eq!(xml, "<Count>42</Count>");
1431    }
1432
1433    #[test]
1434    fn test_serialize_tuple_variant() {
1435        #[derive(Serialize)]
1436        enum Value {
1437            Pair(u32, String),
1438        }
1439
1440        let xml = to_string(&Value::Pair(1, "one".to_string())).unwrap();
1441        assert_eq!(xml, "<Pair><item>1</item><item>one</item></Pair>");
1442    }
1443
1444    #[test]
1445    fn test_serialize_struct_variant() {
1446        #[derive(Serialize)]
1447        enum Value {
1448            Point { x: i32, y: i32 },
1449        }
1450
1451        let xml = to_string(&Value::Point { x: 1, y: 2 }).unwrap();
1452        assert_eq!(xml, "<Point><x>1</x><y>2</y></Point>");
1453    }
1454
1455    #[test]
1456    fn test_serialize_newtype_variant_as_field() {
1457        #[derive(Serialize)]
1458        enum Value {
1459            Count(u32),
1460        }
1461
1462        #[derive(Serialize)]
1463        struct Item {
1464            status: Value,
1465        }
1466
1467        let item = Item {
1468            status: Value::Count(42),
1469        };
1470
1471        let xml = to_string(&item).unwrap();
1472        assert_eq!(xml, "<Item><status><Count>42</Count></status></Item>");
1473    }
1474
1475    #[test]
1476    fn test_serialize_tuple_variant_as_field() {
1477        #[derive(Serialize)]
1478        enum Value {
1479            Pair(u32, String),
1480        }
1481
1482        #[derive(Serialize)]
1483        struct Item {
1484            status: Value,
1485        }
1486
1487        let item = Item {
1488            status: Value::Pair(1, "one".to_string()),
1489        };
1490
1491        let xml = to_string(&item).unwrap();
1492        assert_eq!(
1493            xml,
1494            "<Item><status><Pair><item>1</item><item>one</item></Pair></status></Item>"
1495        );
1496    }
1497
1498    #[test]
1499    fn test_serialize_struct_variant_as_field() {
1500        #[derive(Serialize)]
1501        enum Value {
1502            Point { x: i32, y: i32 },
1503        }
1504
1505        #[derive(Serialize)]
1506        struct Item {
1507            status: Value,
1508        }
1509
1510        let item = Item {
1511            status: Value::Point { x: 1, y: 2 },
1512        };
1513
1514        let xml = to_string(&item).unwrap();
1515        assert_eq!(xml, "<Item><status><Point><x>1</x><y>2</y></Point></status></Item>");
1516    }
1517
1518    #[test]
1519    fn test_exact_output_simple_struct() {
1520        #[derive(Serialize)]
1521        struct Person {
1522            name: String,
1523            age: u32,
1524        }
1525
1526        let person = Person {
1527            name: "Alice".to_string(),
1528            age: 30,
1529        };
1530
1531        let xml = to_string(&person).unwrap();
1532        assert_eq!(xml, "<Person><name>Alice</name><age>30</age></Person>");
1533    }
1534
1535    #[test]
1536    fn test_exact_output_attributes() {
1537        #[derive(Serialize)]
1538        struct Item {
1539            #[serde(rename = "@id")]
1540            id: String,
1541            #[serde(rename = "@class")]
1542            class: String,
1543            name: String,
1544        }
1545
1546        let item = Item {
1547            id: "123".to_string(),
1548            class: "product".to_string(),
1549            name: "Widget".to_string(),
1550        };
1551
1552        let xml = to_string(&item).unwrap();
1553        assert_eq!(xml, r#"<Item id="123" class="product"><name>Widget</name></Item>"#);
1554    }
1555
1556    #[test]
1557    fn test_exact_output_text_content() {
1558        #[derive(Serialize)]
1559        struct Link {
1560            #[serde(rename = "@href")]
1561            href: String,
1562            #[serde(rename = "$value")]
1563            text: String,
1564        }
1565
1566        let link = Link {
1567            href: "https://example.com".to_string(),
1568            text: "Click here".to_string(),
1569        };
1570
1571        let xml = to_string(&link).unwrap();
1572        assert_eq!(xml, r#"<Link href="https://example.com">Click here</Link>"#);
1573    }
1574
1575    #[test]
1576    fn test_with_indent() {
1577        #[derive(Serialize)]
1578        struct Address {
1579            city: String,
1580        }
1581
1582        #[derive(Serialize)]
1583        struct Person {
1584            name: String,
1585            address: Address,
1586        }
1587
1588        let person = Person {
1589            name: "Alice".to_string(),
1590            address: Address {
1591                city: "Springfield".to_string(),
1592            },
1593        };
1594
1595        let mut serializer = Serializer::new().with_indent("  ");
1596        person.serialize(&mut serializer).unwrap();
1597        let xml = serializer.into_string();
1598        assert_eq!(
1599            xml,
1600            "<Person>\n  <name>Alice</name>\n  <address>\n    <city>Springfield</city>\n  </address>\n</Person>"
1601        );
1602    }
1603
1604    #[test]
1605    fn test_serialize_map_char_keys() {
1606        use std::collections::BTreeMap;
1607
1608        let mut map = BTreeMap::new();
1609        map.insert('a', "1");
1610        map.insert('b', "2");
1611
1612        let xml = to_string(&map).unwrap();
1613        assert_eq!(xml, "<map><a>1</a><b>2</b></map>");
1614    }
1615
1616    #[test]
1617    fn test_serialize_map_negative_int_keys() {
1618        use std::collections::BTreeMap;
1619
1620        let mut map = BTreeMap::new();
1621        map.insert(-1i64, "neg");
1622        map.insert(2i64, "pos");
1623
1624        let xml = to_string(&map).unwrap();
1625        assert_eq!(xml, "<map><-1>neg</-1><2>pos</2></map>");
1626    }
1627
1628    #[test]
1629    fn test_serialize_map_bool_keys() {
1630        use std::collections::BTreeMap;
1631
1632        let mut map = BTreeMap::new();
1633        map.insert(false, "no");
1634        map.insert(true, "yes");
1635
1636        let xml = to_string(&map).unwrap();
1637        assert_eq!(xml, "<map><false>no</false><true>yes</true></map>");
1638    }
1639
1640    #[test]
1641    fn test_none_first_field_then_regular() {
1642        #[derive(Serialize)]
1643        struct S {
1644            a: Option<String>,
1645            b: String,
1646        }
1647
1648        let s = S {
1649            a: None,
1650            b: "x".to_string(),
1651        };
1652
1653        // The `None` first field triggers the start-tag rollback; the next
1654        // field must re-emit the start tag cleanly.
1655        let xml = to_string(&s).unwrap();
1656        assert_eq!(xml, "<S><b>x</b></S>");
1657    }
1658
1659    #[test]
1660    fn test_empty_vec_first_field_then_regular() {
1661        #[derive(Serialize)]
1662        struct S {
1663            a: Vec<String>,
1664            b: String,
1665        }
1666
1667        let s = S {
1668            a: vec![],
1669            b: "x".to_string(),
1670        };
1671
1672        // An empty sequence produces no output, so the rollback path runs
1673        // just like for `None`.
1674        let xml = to_string(&s).unwrap();
1675        assert_eq!(xml, "<S><b>x</b></S>");
1676    }
1677
1678    #[test]
1679    fn test_all_none_fields_empty_element() {
1680        #[derive(Serialize)]
1681        struct S {
1682            a: Option<String>,
1683            b: Option<i32>,
1684        }
1685
1686        let s = S { a: None, b: None };
1687
1688        // Every field rolls back, so `end()` emits the self-closing form.
1689        let xml = to_string(&s).unwrap();
1690        assert_eq!(xml, "<S/>");
1691    }
1692
1693    #[test]
1694    fn test_none_first_field_then_attribute() {
1695        #[derive(Serialize)]
1696        struct S {
1697            a: Option<String>,
1698            #[serde(rename = "@id")]
1699            id: String,
1700            b: String,
1701        }
1702
1703        let s = S {
1704            a: None,
1705            id: "7".to_string(),
1706            b: "x".to_string(),
1707        };
1708
1709        // The rollback must leave the serializer in a state where a
1710        // subsequent attribute still lands on the (re-emitted) start tag.
1711        let xml = to_string(&s).unwrap();
1712        assert_eq!(xml, r#"<S id="7"><b>x</b></S>"#);
1713    }
1714
1715    #[test]
1716    fn test_multiple_attributes_after_regular_field() {
1717        #[derive(Serialize)]
1718        struct S {
1719            name: String,
1720            #[serde(rename = "@id")]
1721            id: String,
1722            #[serde(rename = "@cls")]
1723            cls: String,
1724        }
1725
1726        let s = S {
1727            name: "w".to_string(),
1728            id: "7".to_string(),
1729            cls: "a".to_string(),
1730        };
1731
1732        // Both late attributes are spliced into the already-written start
1733        // tag, in declaration order.
1734        let xml = to_string(&s).unwrap();
1735        assert_eq!(xml, r#"<S id="7" cls="a"><name>w</name></S>"#);
1736    }
1737
1738    #[test]
1739    fn test_attribute_after_nested_child() {
1740        #[derive(Serialize)]
1741        struct Inner {
1742            v: String,
1743        }
1744
1745        #[derive(Serialize)]
1746        struct Outer {
1747            child: Inner,
1748            #[serde(rename = "@id")]
1749            id: String,
1750        }
1751
1752        let outer = Outer {
1753            child: Inner {
1754                v: "x".to_string(),
1755            },
1756            id: "7".to_string(),
1757        };
1758
1759        // The late attribute must be spliced into the outer start tag, not
1760        // anywhere inside the nested child that was streamed before it.
1761        let xml = to_string(&outer).unwrap();
1762        assert_eq!(xml, r#"<Outer id="7"><child><v>x</v></child></Outer>"#);
1763    }
1764}