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;
37
38/// Serializes a value to an XML string.
39///
40/// # Example
41///
42/// ```
43/// use serde::Serialize;
44/// use serde_xml::to_string;
45///
46/// #[derive(Serialize)]
47/// struct Person {
48///     name: String,
49///     age: u32,
50/// }
51///
52/// let person = Person {
53///     name: "Alice".to_string(),
54///     age: 30,
55/// };
56///
57/// let xml = to_string(&person).unwrap();
58/// assert!(xml.contains("<name>Alice</name>"));
59/// ```
60pub fn to_string<T>(value: &T) -> Result<String>
61where
62    T: Serialize + ?Sized,
63{
64    let mut serializer = Serializer::new();
65    value.serialize(&mut serializer)?;
66    Ok(serializer.into_string())
67}
68
69/// Serializes a value to an XML string with a root element name.
70pub fn to_string_with_root<T>(value: &T, root: &str) -> Result<String>
71where
72    T: Serialize + ?Sized,
73{
74    let mut serializer = Serializer::with_root(root);
75    value.serialize(&mut serializer)?;
76    Ok(serializer.into_string())
77}
78
79/// Serializes a value to XML bytes.
80pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
81where
82    T: Serialize + ?Sized,
83{
84    Ok(to_string(value)?.into_bytes())
85}
86
87/// Serializes a value to a writer.
88pub fn to_writer<W, T>(writer: W, value: &T) -> Result<()>
89where
90    W: Write,
91    T: Serialize + ?Sized,
92{
93    let xml = to_string(value)?;
94    let mut writer = writer;
95    writer.write_all(xml.as_bytes())?;
96    Ok(())
97}
98
99/// The XML serializer.
100pub struct Serializer {
101    output: String,
102    /// Root element name (for when we don't have type name info).
103    root: Option<String>,
104    /// Current element name.
105    current_element: Option<String>,
106    /// Stack of element names for nested structures.
107    element_stack: Vec<String>,
108    /// Whether we're serializing a map key.
109    is_key: bool,
110    /// Current key for map entries.
111    current_key: Option<String>,
112    /// Whether to include XML declaration.
113    include_declaration: bool,
114    /// Indentation level.
115    indent_level: usize,
116    /// Indentation string.
117    indent_str: Option<String>,
118}
119
120impl Serializer {
121    /// Creates a new serializer.
122    pub fn new() -> Self {
123        Self {
124            output: String::new(),
125            root: None,
126            current_element: None,
127            element_stack: Vec::new(),
128            is_key: false,
129            current_key: None,
130            include_declaration: false,
131            indent_level: 0,
132            indent_str: None,
133        }
134    }
135
136    /// Creates a new serializer with a root element name.
137    pub fn with_root(root: &str) -> Self {
138        Self {
139            root: Some(root.to_string()),
140            ..Self::new()
141        }
142    }
143
144    /// Enables pretty-printing with the given indentation.
145    pub fn with_indent(mut self, indent: &str) -> Self {
146        self.indent_str = Some(indent.to_string());
147        self
148    }
149
150    /// Includes XML declaration in the output.
151    pub fn with_declaration(mut self) -> Self {
152        self.include_declaration = true;
153        self
154    }
155
156    /// Returns the serialized XML string.
157    pub fn into_string(self) -> String {
158        self.output
159    }
160
161    /// Writes an opening tag.
162    fn write_start_tag(&mut self, name: &str) {
163        self.write_indent();
164        self.output.push('<');
165        self.output.push_str(name);
166        self.output.push('>');
167        self.element_stack.push(name.to_string());
168        self.indent_level += 1;
169    }
170
171    /// Writes an opening tag with attributes.
172    fn write_start_tag_with_attrs(&mut self, name: &str, attrs: &[(String, String)]) {
173        self.write_indent();
174        self.output.push('<');
175        self.output.push_str(name);
176        for (attr_name, attr_value) in attrs {
177            self.output.push(' ');
178            self.output.push_str(attr_name);
179            self.output.push_str("=\"");
180            self.output.push_str(&escape(attr_value));
181            self.output.push('"');
182        }
183        self.output.push('>');
184        self.element_stack.push(name.to_string());
185        self.indent_level += 1;
186    }
187
188    /// Writes a closing tag.
189    fn write_end_tag(&mut self) {
190        self.indent_level = self.indent_level.saturating_sub(1);
191
192        if let Some(name) = self.element_stack.pop() {
193            self.write_indent();
194            self.output.push_str("</");
195            self.output.push_str(&name);
196            self.output.push('>');
197        }
198    }
199
200    /// Writes an empty element.
201    fn write_empty_element(&mut self, name: &str) {
202        self.write_indent();
203        self.output.push('<');
204        self.output.push_str(name);
205        self.output.push_str("/>");
206    }
207
208    /// Writes an empty element with attributes.
209    fn write_empty_element_with_attrs(&mut self, name: &str, attrs: &[(String, String)]) {
210        self.write_indent();
211        self.output.push('<');
212        self.output.push_str(name);
213        for (attr_name, attr_value) in attrs {
214            self.output.push(' ');
215            self.output.push_str(attr_name);
216            self.output.push_str("=\"");
217            self.output.push_str(&escape(attr_value));
218            self.output.push('"');
219        }
220        self.output.push_str("/>");
221    }
222
223    /// Writes a complete element with text content.
224    fn write_element(&mut self, name: &str, content: &str) {
225        self.write_indent();
226        self.output.push('<');
227        self.output.push_str(name);
228        self.output.push('>');
229        self.output.push_str(&escape(content));
230        self.output.push_str("</");
231        self.output.push_str(name);
232        self.output.push('>');
233    }
234
235    /// Writes text content.
236    fn write_text(&mut self, content: &str) {
237        self.output.push_str(&escape(content));
238    }
239
240    /// Writes indentation if configured.
241    fn write_indent(&mut self) {
242        if let Some(ref indent) = self.indent_str {
243            if !self.output.is_empty() && !self.output.ends_with('\n') {
244                self.output.push('\n');
245            }
246            for _ in 0..self.indent_level.saturating_sub(1) {
247                self.output.push_str(indent);
248            }
249        }
250    }
251
252    /// Gets the current element name.
253    fn get_element_name(&self, fallback: &str) -> String {
254        self.current_key
255            .clone()
256            .or_else(|| self.current_element.clone())
257            .or_else(|| self.root.clone())
258            .unwrap_or_else(|| fallback.to_string())
259    }
260}
261
262impl Default for Serializer {
263    fn default() -> Self {
264        Self::new()
265    }
266}
267
268impl<'a> ser::Serializer for &'a mut Serializer {
269    type Ok = ();
270    type Error = Error;
271
272    type SerializeSeq = SeqSerializer<'a>;
273    type SerializeTuple = SeqSerializer<'a>;
274    type SerializeTupleStruct = SeqSerializer<'a>;
275    type SerializeTupleVariant = SeqSerializer<'a>;
276    type SerializeMap = MapSerializer<'a>;
277    type SerializeStruct = StructSerializer<'a>;
278    type SerializeStructVariant = StructSerializer<'a>;
279
280    fn serialize_bool(self, v: bool) -> Result<()> {
281        let text = if v { "true" } else { "false" };
282        if let Some(ref key) = self.current_key.take() {
283            self.write_element(key, text);
284        } else {
285            self.write_text(text);
286        }
287        Ok(())
288    }
289
290    fn serialize_i8(self, v: i8) -> Result<()> {
291        self.serialize_i64(v as i64)
292    }
293
294    fn serialize_i16(self, v: i16) -> Result<()> {
295        self.serialize_i64(v as i64)
296    }
297
298    fn serialize_i32(self, v: i32) -> Result<()> {
299        self.serialize_i64(v as i64)
300    }
301
302    fn serialize_i64(self, v: i64) -> Result<()> {
303        let mut buffer = itoa::Buffer::new();
304        let text = buffer.format(v);
305        if let Some(ref key) = self.current_key.take() {
306            self.write_element(key, text);
307        } else {
308            self.write_text(text);
309        }
310        Ok(())
311    }
312
313    fn serialize_u8(self, v: u8) -> Result<()> {
314        self.serialize_u64(v as u64)
315    }
316
317    fn serialize_u16(self, v: u16) -> Result<()> {
318        self.serialize_u64(v as u64)
319    }
320
321    fn serialize_u32(self, v: u32) -> Result<()> {
322        self.serialize_u64(v as u64)
323    }
324
325    fn serialize_u64(self, v: u64) -> Result<()> {
326        let mut buffer = itoa::Buffer::new();
327        let text = buffer.format(v);
328        if let Some(ref key) = self.current_key.take() {
329            self.write_element(key, text);
330        } else {
331            self.write_text(text);
332        }
333        Ok(())
334    }
335
336    fn serialize_f32(self, v: f32) -> Result<()> {
337        self.serialize_f64(v as f64)
338    }
339
340    fn serialize_f64(self, v: f64) -> Result<()> {
341        let mut buffer = ryu::Buffer::new();
342        let text = buffer.format(v);
343        if let Some(ref key) = self.current_key.take() {
344            self.write_element(key, text);
345        } else {
346            self.write_text(text);
347        }
348        Ok(())
349    }
350
351    fn serialize_char(self, v: char) -> Result<()> {
352        let mut buf = [0u8; 4];
353        let text = v.encode_utf8(&mut buf);
354        if let Some(ref key) = self.current_key.take() {
355            self.write_element(key, text);
356        } else {
357            self.write_text(text);
358        }
359        Ok(())
360    }
361
362    fn serialize_str(self, v: &str) -> Result<()> {
363        if self.is_key {
364            self.current_key = Some(v.to_string());
365            self.is_key = false;
366        } else if let Some(ref key) = self.current_key.take() {
367            self.write_element(key, v);
368        } else {
369            self.write_text(v);
370        }
371        Ok(())
372    }
373
374    fn serialize_bytes(self, v: &[u8]) -> Result<()> {
375        // Hex encode bytes
376        use std::fmt::Write;
377        let mut encoded = String::new();
378        for byte in v {
379            write!(&mut encoded, "{:02x}", byte).unwrap();
380        }
381        if let Some(ref key) = self.current_key.take() {
382            self.write_element(key, &encoded);
383        } else {
384            self.write_text(&encoded);
385        }
386        Ok(())
387    }
388
389    fn serialize_none(self) -> Result<()> {
390        // Don't output anything for None
391        self.current_key = None;
392        Ok(())
393    }
394
395    fn serialize_some<T>(self, value: &T) -> Result<()>
396    where
397        T: Serialize + ?Sized,
398    {
399        value.serialize(self)
400    }
401
402    fn serialize_unit(self) -> Result<()> {
403        if let Some(ref key) = self.current_key.take() {
404            self.write_empty_element(key);
405        }
406        Ok(())
407    }
408
409    fn serialize_unit_struct(self, name: &'static str) -> Result<()> {
410        let elem_name = self.get_element_name(name);
411        self.write_empty_element(&elem_name);
412        Ok(())
413    }
414
415    fn serialize_unit_variant(
416        self,
417        _name: &'static str,
418        _variant_index: u32,
419        variant: &'static str,
420    ) -> Result<()> {
421        if let Some(ref key) = self.current_key.take() {
422            self.write_element(key, variant);
423        } else {
424            self.write_empty_element(variant);
425        }
426        Ok(())
427    }
428
429    fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<()>
430    where
431        T: Serialize + ?Sized,
432    {
433        self.current_element = Some(name.to_string());
434        value.serialize(self)
435    }
436
437    fn serialize_newtype_variant<T>(
438        self,
439        _name: &'static str,
440        _variant_index: u32,
441        variant: &'static str,
442        value: &T,
443    ) -> Result<()>
444    where
445        T: Serialize + ?Sized,
446    {
447        self.write_start_tag(variant);
448        value.serialize(&mut *self)?;
449        self.write_end_tag();
450        Ok(())
451    }
452
453    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
454        let element_name = self.current_key.take().unwrap_or_else(|| "item".to_string());
455        Ok(SeqSerializer {
456            ser: self,
457            element_name,
458        })
459    }
460
461    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
462        self.serialize_seq(Some(len))
463    }
464
465    fn serialize_tuple_struct(
466        self,
467        name: &'static str,
468        _len: usize,
469    ) -> Result<Self::SerializeTupleStruct> {
470        self.write_start_tag(name);
471        Ok(SeqSerializer {
472            ser: self,
473            element_name: "item".to_string(),
474        })
475    }
476
477    fn serialize_tuple_variant(
478        self,
479        _name: &'static str,
480        _variant_index: u32,
481        variant: &'static str,
482        _len: usize,
483    ) -> Result<Self::SerializeTupleVariant> {
484        self.write_start_tag(variant);
485        Ok(SeqSerializer {
486            ser: self,
487            element_name: "item".to_string(),
488        })
489    }
490
491    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
492        let name = self.current_key.take()
493            .or_else(|| self.root.clone())
494            .unwrap_or_else(|| "map".to_string());
495        self.write_start_tag(&name);
496        Ok(MapSerializer { ser: self })
497    }
498
499    fn serialize_struct(self, name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
500        let elem_name = self.current_key.take().unwrap_or_else(|| name.to_string());
501        // Don't write start tag yet - collect attributes first
502        Ok(StructSerializer {
503            ser: self,
504            elem_name,
505            attrs: Vec::new(),
506            children: Vec::new(),
507            text_content: None,
508            started: false,
509        })
510    }
511
512    fn serialize_struct_variant(
513        self,
514        _name: &'static str,
515        _variant_index: u32,
516        variant: &'static str,
517        _len: usize,
518    ) -> Result<Self::SerializeStructVariant> {
519        Ok(StructSerializer {
520            ser: self,
521            elem_name: variant.to_string(),
522            attrs: Vec::new(),
523            children: Vec::new(),
524            text_content: None,
525            started: false,
526        })
527    }
528}
529
530/// Simple serializer for attribute values (no XML escaping - escaping done at output).
531struct AttrValueSerializer {
532    output: String,
533}
534
535impl AttrValueSerializer {
536    fn new() -> Self {
537        Self { output: String::new() }
538    }
539
540    fn into_string(self) -> String {
541        self.output
542    }
543}
544
545impl ser::Serializer for &mut AttrValueSerializer {
546    type Ok = ();
547    type Error = Error;
548
549    type SerializeSeq = ser::Impossible<(), Error>;
550    type SerializeTuple = ser::Impossible<(), Error>;
551    type SerializeTupleStruct = ser::Impossible<(), Error>;
552    type SerializeTupleVariant = ser::Impossible<(), Error>;
553    type SerializeMap = ser::Impossible<(), Error>;
554    type SerializeStruct = ser::Impossible<(), Error>;
555    type SerializeStructVariant = ser::Impossible<(), Error>;
556
557    fn serialize_bool(self, v: bool) -> Result<()> {
558        self.output.push_str(if v { "true" } else { "false" });
559        Ok(())
560    }
561
562    fn serialize_i8(self, v: i8) -> Result<()> { self.serialize_i64(v as i64) }
563    fn serialize_i16(self, v: i16) -> Result<()> { self.serialize_i64(v as i64) }
564    fn serialize_i32(self, v: i32) -> Result<()> { self.serialize_i64(v as i64) }
565    fn serialize_i64(self, v: i64) -> Result<()> {
566        let mut buffer = itoa::Buffer::new();
567        self.output.push_str(buffer.format(v));
568        Ok(())
569    }
570
571    fn serialize_u8(self, v: u8) -> Result<()> { self.serialize_u64(v as u64) }
572    fn serialize_u16(self, v: u16) -> Result<()> { self.serialize_u64(v as u64) }
573    fn serialize_u32(self, v: u32) -> Result<()> { self.serialize_u64(v as u64) }
574    fn serialize_u64(self, v: u64) -> Result<()> {
575        let mut buffer = itoa::Buffer::new();
576        self.output.push_str(buffer.format(v));
577        Ok(())
578    }
579
580    fn serialize_f32(self, v: f32) -> Result<()> { self.serialize_f64(v as f64) }
581    fn serialize_f64(self, v: f64) -> Result<()> {
582        let mut buffer = ryu::Buffer::new();
583        self.output.push_str(buffer.format(v));
584        Ok(())
585    }
586
587    fn serialize_char(self, v: char) -> Result<()> {
588        self.output.push(v);
589        Ok(())
590    }
591
592    fn serialize_str(self, v: &str) -> Result<()> {
593        // No escaping here - escaping happens when writing the attribute
594        self.output.push_str(v);
595        Ok(())
596    }
597
598    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
599        Err(Error::unsupported("bytes in attribute"))
600    }
601
602    fn serialize_none(self) -> Result<()> { Ok(()) }
603    fn serialize_some<T: ?Sized + Serialize>(self, v: &T) -> Result<()> { v.serialize(self) }
604    fn serialize_unit(self) -> Result<()> { Ok(()) }
605    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { Ok(()) }
606    fn serialize_unit_variant(self, _name: &'static str, _idx: u32, variant: &'static str) -> Result<()> {
607        self.output.push_str(variant);
608        Ok(())
609    }
610    fn serialize_newtype_struct<T: ?Sized + Serialize>(self, _name: &'static str, v: &T) -> Result<()> {
611        v.serialize(self)
612    }
613    fn serialize_newtype_variant<T: ?Sized + Serialize>(self, _name: &'static str, _idx: u32, _variant: &'static str, v: &T) -> Result<()> {
614        v.serialize(self)
615    }
616
617    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
618        Err(Error::unsupported("sequence in attribute"))
619    }
620    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
621        Err(Error::unsupported("tuple in attribute"))
622    }
623    fn serialize_tuple_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeTupleStruct> {
624        Err(Error::unsupported("tuple struct in attribute"))
625    }
626    fn serialize_tuple_variant(self, _name: &'static str, _idx: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeTupleVariant> {
627        Err(Error::unsupported("tuple variant in attribute"))
628    }
629    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
630        Err(Error::unsupported("map in attribute"))
631    }
632    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
633        Err(Error::unsupported("struct in attribute"))
634    }
635    fn serialize_struct_variant(self, _name: &'static str, _idx: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeStructVariant> {
636        Err(Error::unsupported("struct variant in attribute"))
637    }
638}
639
640/// Sequence serializer.
641pub struct SeqSerializer<'a> {
642    ser: &'a mut Serializer,
643    element_name: String,
644}
645
646impl<'a> ser::SerializeSeq for SeqSerializer<'a> {
647    type Ok = ();
648    type Error = Error;
649
650    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
651    where
652        T: Serialize + ?Sized,
653    {
654        self.ser.current_key = Some(self.element_name.clone());
655        value.serialize(&mut *self.ser)
656    }
657
658    fn end(self) -> Result<()> {
659        Ok(())
660    }
661}
662
663impl<'a> ser::SerializeTuple for SeqSerializer<'a> {
664    type Ok = ();
665    type Error = Error;
666
667    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
668    where
669        T: Serialize + ?Sized,
670    {
671        ser::SerializeSeq::serialize_element(self, value)
672    }
673
674    fn end(self) -> Result<()> {
675        ser::SerializeSeq::end(self)
676    }
677}
678
679impl<'a> ser::SerializeTupleStruct for SeqSerializer<'a> {
680    type Ok = ();
681    type Error = Error;
682
683    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
684    where
685        T: Serialize + ?Sized,
686    {
687        self.ser.current_key = Some(self.element_name.clone());
688        value.serialize(&mut *self.ser)
689    }
690
691    fn end(self) -> Result<()> {
692        self.ser.write_end_tag();
693        Ok(())
694    }
695}
696
697impl<'a> ser::SerializeTupleVariant for SeqSerializer<'a> {
698    type Ok = ();
699    type Error = Error;
700
701    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
702    where
703        T: Serialize + ?Sized,
704    {
705        self.ser.current_key = Some(self.element_name.clone());
706        value.serialize(&mut *self.ser)
707    }
708
709    fn end(self) -> Result<()> {
710        self.ser.write_end_tag();
711        Ok(())
712    }
713}
714
715/// Map serializer.
716pub struct MapSerializer<'a> {
717    ser: &'a mut Serializer,
718}
719
720impl<'a> ser::SerializeMap for MapSerializer<'a> {
721    type Ok = ();
722    type Error = Error;
723
724    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
725    where
726        T: Serialize + ?Sized,
727    {
728        self.ser.is_key = true;
729        key.serialize(&mut *self.ser)
730    }
731
732    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
733    where
734        T: Serialize + ?Sized,
735    {
736        value.serialize(&mut *self.ser)
737    }
738
739    fn end(self) -> Result<()> {
740        self.ser.write_end_tag();
741        Ok(())
742    }
743}
744
745/// Struct serializer with attribute support.
746pub struct StructSerializer<'a> {
747    ser: &'a mut Serializer,
748    elem_name: String,
749    attrs: Vec<(String, String)>,
750    children: Vec<String>,
751    text_content: Option<String>,
752    started: bool,
753}
754
755impl<'a> StructSerializer<'a> {
756    fn ensure_started(&mut self) {
757        if !self.started {
758            self.ser.write_start_tag_with_attrs(&self.elem_name, &self.attrs);
759            // Write any buffered children
760            for child in &self.children {
761                self.ser.output.push_str(child);
762            }
763            self.children.clear();
764            self.started = true;
765        }
766    }
767}
768
769impl<'a> ser::SerializeStruct for StructSerializer<'a> {
770    type Ok = ();
771    type Error = Error;
772
773    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
774    where
775        T: Serialize + ?Sized,
776    {
777        // Check if this is an attribute (starts with @)
778        if let Some(attr_name) = key.strip_prefix('@') {
779            // Serialize value to string - use a special mode that doesn't escape
780            let mut attr_ser = AttrValueSerializer::new();
781            value.serialize(&mut attr_ser)?;
782            let attr_value = attr_ser.into_string();
783            self.attrs.push((attr_name.to_string(), attr_value));
784            return Ok(());
785        }
786
787        // Check if this is text content ($value or $text)
788        if key == "$value" || key == "$text" {
789            // Serialize value to string
790            let mut text_ser = Serializer::new();
791            value.serialize(&mut text_ser)?;
792            self.text_content = Some(text_ser.into_string());
793            return Ok(());
794        }
795
796        // Regular field - ensure element started
797        self.ensure_started();
798        self.ser.current_key = Some(key.to_string());
799        value.serialize(&mut *self.ser)
800    }
801
802    fn end(self) -> Result<()> {
803        if self.started {
804            // Write text content if any
805            if let Some(text) = self.text_content {
806                self.ser.output.push_str(&text);
807            }
808            self.ser.write_end_tag();
809        } else if self.attrs.is_empty() && self.text_content.is_none() {
810            // Empty element with no attributes
811            self.ser.write_empty_element(&self.elem_name);
812        } else if let Some(text) = self.text_content {
813            // Element with just text content and possibly attributes
814            self.ser.write_start_tag_with_attrs(&self.elem_name, &self.attrs);
815            self.ser.output.push_str(&text);
816            self.ser.write_end_tag();
817        } else {
818            // Element with only attributes
819            self.ser.write_empty_element_with_attrs(&self.elem_name, &self.attrs);
820        }
821        Ok(())
822    }
823}
824
825impl<'a> ser::SerializeStructVariant for StructSerializer<'a> {
826    type Ok = ();
827    type Error = Error;
828
829    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
830    where
831        T: Serialize + ?Sized,
832    {
833        ser::SerializeStruct::serialize_field(self, key, value)
834    }
835
836    fn end(self) -> Result<()> {
837        ser::SerializeStruct::end(self)
838    }
839}
840
841#[cfg(test)]
842mod tests {
843    use super::*;
844    use serde::Serialize;
845
846    #[test]
847    fn test_serialize_simple_struct() {
848        #[derive(Serialize)]
849        struct Person {
850            name: String,
851            age: u32,
852        }
853
854        let person = Person {
855            name: "Alice".to_string(),
856            age: 30,
857        };
858
859        let xml = to_string(&person).unwrap();
860        assert!(xml.contains("<Person>"));
861        assert!(xml.contains("<name>Alice</name>"));
862        assert!(xml.contains("<age>30</age>"));
863        assert!(xml.contains("</Person>"));
864    }
865
866    #[test]
867    fn test_serialize_with_attributes() {
868        #[derive(Serialize)]
869        struct Element {
870            #[serde(rename = "@id")]
871            id: String,
872            #[serde(rename = "@class")]
873            class: String,
874            content: String,
875        }
876
877        let elem = Element {
878            id: "main".to_string(),
879            class: "container".to_string(),
880            content: "Hello".to_string(),
881        };
882
883        let xml = to_string(&elem).unwrap();
884        assert!(xml.contains(r#"id="main""#));
885        assert!(xml.contains(r#"class="container""#));
886        assert!(xml.contains("<content>Hello</content>"));
887    }
888
889    #[test]
890    fn test_serialize_attributes_only() {
891        #[derive(Serialize)]
892        struct EmptyElement {
893            #[serde(rename = "@id")]
894            id: String,
895            #[serde(rename = "@disabled")]
896            disabled: bool,
897        }
898
899        let elem = EmptyElement {
900            id: "btn".to_string(),
901            disabled: true,
902        };
903
904        let xml = to_string(&elem).unwrap();
905        assert!(xml.contains(r#"id="btn""#));
906        assert!(xml.contains(r#"disabled="true""#));
907        assert!(xml.contains("/>") || xml.contains("</EmptyElement>"));
908    }
909
910    #[test]
911    fn test_serialize_text_content() {
912        #[derive(Serialize)]
913        struct TextElement {
914            #[serde(rename = "@id")]
915            id: String,
916            #[serde(rename = "$value")]
917            text: String,
918        }
919
920        let elem = TextElement {
921            id: "para".to_string(),
922            text: "Hello World".to_string(),
923        };
924
925        let xml = to_string(&elem).unwrap();
926        assert!(xml.contains(r#"id="para""#));
927        assert!(xml.contains("Hello World"));
928    }
929
930    #[test]
931    fn test_serialize_nested_struct() {
932        #[derive(Serialize)]
933        struct Address {
934            city: String,
935            country: String,
936        }
937
938        #[derive(Serialize)]
939        struct Person {
940            name: String,
941            address: Address,
942        }
943
944        let person = Person {
945            name: "Bob".to_string(),
946            address: Address {
947                city: "New York".to_string(),
948                country: "USA".to_string(),
949            },
950        };
951
952        let xml = to_string(&person).unwrap();
953        assert!(xml.contains("<address>"));
954        assert!(xml.contains("<city>New York</city>"));
955        assert!(xml.contains("</address>"));
956    }
957
958    #[test]
959    fn test_serialize_optional() {
960        #[derive(Serialize)]
961        struct Config {
962            name: String,
963            value: Option<String>,
964        }
965
966        let with_value = Config {
967            name: "test".to_string(),
968            value: Some("val".to_string()),
969        };
970        let xml = to_string(&with_value).unwrap();
971        assert!(xml.contains("<value>val</value>"));
972
973        let without_value = Config {
974            name: "test".to_string(),
975            value: None,
976        };
977        let xml = to_string(&without_value).unwrap();
978        assert!(!xml.contains("<value>"));
979    }
980
981    #[test]
982    fn test_serialize_vector() {
983        #[derive(Serialize)]
984        struct Items {
985            items: Vec<String>,
986        }
987
988        let items = Items {
989            items: vec!["one".to_string(), "two".to_string(), "three".to_string()],
990        };
991
992        let xml = to_string(&items).unwrap();
993        assert!(xml.contains("<items>one</items>"));
994        assert!(xml.contains("<items>two</items>"));
995        assert!(xml.contains("<items>three</items>"));
996    }
997
998    #[test]
999    fn test_serialize_escaped_content() {
1000        #[derive(Serialize)]
1001        struct Data {
1002            content: String,
1003        }
1004
1005        let data = Data {
1006            content: "<hello> & \"world\"".to_string(),
1007        };
1008
1009        let xml = to_string(&data).unwrap();
1010        assert!(xml.contains("&lt;hello&gt;"));
1011        assert!(xml.contains("&amp;"));
1012        assert!(xml.contains("&quot;"));
1013    }
1014
1015    #[test]
1016    fn test_serialize_escaped_attribute() {
1017        #[derive(Serialize)]
1018        struct Element {
1019            #[serde(rename = "@title")]
1020            title: String,
1021        }
1022
1023        let elem = Element {
1024            title: "Hello \"World\" & <Friends>".to_string(),
1025        };
1026
1027        let xml = to_string(&elem).unwrap();
1028        assert!(xml.contains("&quot;"));
1029        assert!(xml.contains("&amp;"));
1030        assert!(xml.contains("&lt;"));
1031    }
1032
1033    #[test]
1034    fn test_serialize_bool() {
1035        #[derive(Serialize)]
1036        struct Flags {
1037            enabled: bool,
1038            active: bool,
1039        }
1040
1041        let flags = Flags {
1042            enabled: true,
1043            active: false,
1044        };
1045
1046        let xml = to_string(&flags).unwrap();
1047        assert!(xml.contains("<enabled>true</enabled>"));
1048        assert!(xml.contains("<active>false</active>"));
1049    }
1050
1051    #[test]
1052    fn test_serialize_numbers() {
1053        #[derive(Serialize)]
1054        struct Numbers {
1055            i: i32,
1056            u: u64,
1057            f: f64,
1058        }
1059
1060        let nums = Numbers {
1061            i: -42,
1062            u: 100,
1063            f: 1.234,
1064        };
1065
1066        let xml = to_string(&nums).unwrap();
1067        assert!(xml.contains("<i>-42</i>"));
1068        assert!(xml.contains("<u>100</u>"));
1069        assert!(xml.contains("<f>1.234</f>"));
1070    }
1071
1072    #[test]
1073    fn test_serialize_enum() {
1074        #[derive(Serialize)]
1075        enum Status {
1076            Active,
1077            #[allow(dead_code)]
1078            Inactive,
1079            #[allow(dead_code)]
1080            Pending,
1081        }
1082
1083        #[derive(Serialize)]
1084        struct Item {
1085            status: Status,
1086        }
1087
1088        let item = Item {
1089            status: Status::Active,
1090        };
1091
1092        let xml = to_string(&item).unwrap();
1093        assert!(xml.contains("<status>Active</status>") || xml.contains("<Active/>"));
1094    }
1095
1096    #[test]
1097    fn test_serialize_unit_struct() {
1098        #[derive(Serialize)]
1099        struct Empty;
1100
1101        let xml = to_string(&Empty).unwrap();
1102        assert!(xml.contains("<Empty/>"));
1103    }
1104
1105    #[test]
1106    fn test_serialize_char() {
1107        #[derive(Serialize)]
1108        struct Data {
1109            c: char,
1110        }
1111
1112        let data = Data { c: 'A' };
1113        let xml = to_string(&data).unwrap();
1114        assert!(xml.contains("<c>A</c>"));
1115    }
1116
1117    #[test]
1118    fn test_to_vec() {
1119        #[derive(Serialize)]
1120        struct Data {
1121            value: String,
1122        }
1123
1124        let data = Data {
1125            value: "test".to_string(),
1126        };
1127
1128        let bytes = to_vec(&data).unwrap();
1129        let xml = String::from_utf8(bytes).unwrap();
1130        assert!(xml.contains("<value>test</value>"));
1131    }
1132
1133    #[test]
1134    fn test_to_writer() {
1135        #[derive(Serialize)]
1136        struct Data {
1137            value: String,
1138        }
1139
1140        let data = Data {
1141            value: "test".to_string(),
1142        };
1143
1144        let mut buffer = Vec::new();
1145        to_writer(&mut buffer, &data).unwrap();
1146        let xml = String::from_utf8(buffer).unwrap();
1147        assert!(xml.contains("<value>test</value>"));
1148    }
1149
1150    #[test]
1151    fn test_with_root() {
1152        #[derive(Serialize)]
1153        struct Data {
1154            value: String,
1155        }
1156
1157        let data = Data {
1158            value: "test".to_string(),
1159        };
1160
1161        let xml = to_string_with_root(&data, "root").unwrap();
1162        // The struct name takes precedence, but root is used for maps
1163        assert!(xml.contains("<value>test</value>"));
1164    }
1165
1166    #[test]
1167    fn test_complex_with_attributes() {
1168        #[derive(Serialize)]
1169        struct Item {
1170            #[serde(rename = "@id")]
1171            id: u32,
1172            #[serde(rename = "@class")]
1173            class: String,
1174            name: String,
1175            value: i32,
1176        }
1177
1178        #[derive(Serialize)]
1179        struct Container {
1180            #[serde(rename = "@version")]
1181            version: String,
1182            item: Vec<Item>,
1183        }
1184
1185        let container = Container {
1186            version: "1.0".to_string(),
1187            item: vec![
1188                Item {
1189                    id: 1,
1190                    class: "primary".to_string(),
1191                    name: "First".to_string(),
1192                    value: 100,
1193                },
1194                Item {
1195                    id: 2,
1196                    class: "secondary".to_string(),
1197                    name: "Second".to_string(),
1198                    value: 200,
1199                },
1200            ],
1201        };
1202
1203        let xml = to_string(&container).unwrap();
1204        assert!(xml.contains(r#"version="1.0""#));
1205        assert!(xml.contains(r#"id="1""#));
1206        assert!(xml.contains(r#"class="primary""#));
1207        assert!(xml.contains("<name>First</name>"));
1208    }
1209}