facet_xml/
serialize.rs

1//! XML serialization implementation.
2
3use std::collections::HashMap;
4use std::io::Write;
5
6use base64::Engine;
7use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
8use facet_core::{Def, Facet, Field, Shape, StructKind};
9use facet_reflect::{HasFields, Peek, is_spanned_shape};
10
11use crate::annotation::{XmlAnnotationPhase, fields_missing_xml_annotations};
12use crate::deserialize::{XmlFieldExt, XmlShapeExt};
13use crate::error::{MissingAnnotationPhase, XmlError, XmlErrorKind};
14
15/// A function that formats a floating-point number to a writer.
16///
17/// This is used to customize how `f32` and `f64` values are serialized to XML.
18/// The function receives the value (as `f64`, with `f32` values upcast) and
19/// a writer to write the formatted output to.
20pub type FloatFormatter = fn(f64, &mut dyn Write) -> std::io::Result<()>;
21
22/// Options for XML serialization.
23#[derive(Clone)]
24pub struct SerializeOptions {
25    /// Whether to pretty-print with indentation (default: false)
26    pub pretty: bool,
27    /// Indentation string for pretty-printing (default: "  ")
28    pub indent: &'static str,
29    /// Custom formatter for floating-point numbers (f32 and f64).
30    /// If `None`, uses the default `Display` implementation.
31    pub float_formatter: Option<FloatFormatter>,
32}
33
34impl Default for SerializeOptions {
35    fn default() -> Self {
36        Self {
37            pretty: false,
38            indent: "  ",
39            float_formatter: None,
40        }
41    }
42}
43
44impl std::fmt::Debug for SerializeOptions {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        f.debug_struct("SerializeOptions")
47            .field("pretty", &self.pretty)
48            .field("indent", &self.indent)
49            .field("float_formatter", &self.float_formatter.map(|_| "..."))
50            .finish()
51    }
52}
53
54impl SerializeOptions {
55    /// Create new default options (compact output).
56    pub fn new() -> Self {
57        Self::default()
58    }
59
60    /// Enable pretty-printing with default indentation.
61    pub fn pretty(mut self) -> Self {
62        self.pretty = true;
63        self
64    }
65
66    /// Set a custom indentation string (implies pretty-printing).
67    pub fn indent(mut self, indent: &'static str) -> Self {
68        self.indent = indent;
69        self.pretty = true;
70        self
71    }
72
73    /// Get the indent string if pretty-printing is enabled, otherwise None.
74    fn indent_str(&self) -> Option<&str> {
75        if self.pretty { Some(self.indent) } else { None }
76    }
77
78    /// Set a custom formatter for floating-point numbers (f32 and f64).
79    ///
80    /// The formatter function receives the value as `f64` (f32 values are upcast)
81    /// and writes the formatted output to the provided writer.
82    ///
83    /// # Example
84    ///
85    /// ```
86    /// # use facet::Facet;
87    /// # use facet_xml as xml;
88    /// # use facet_xml::{to_string_with_options, SerializeOptions};
89    /// # use std::io::Write;
90    /// fn fmt_g(value: f64, w: &mut dyn Write) -> std::io::Result<()> {
91    ///     // Format like C's %g: 6 significant digits, trim trailing zeros
92    ///     let s = format!("{:.6}", value);
93    ///     let s = s.trim_end_matches('0').trim_end_matches('.');
94    ///     write!(w, "{}", s)
95    /// }
96    ///
97    /// #[derive(Facet)]
98    /// struct Point {
99    ///     #[facet(xml::attribute)]
100    ///     x: f64,
101    ///     #[facet(xml::attribute)]
102    ///     y: f64,
103    /// }
104    ///
105    /// let point = Point { x: 1.5, y: 2.0 };
106    /// let options = SerializeOptions::new().float_formatter(fmt_g);
107    /// let xml = to_string_with_options(&point, &options).unwrap();
108    /// assert_eq!(xml, r#"<Point x="1.5" y="2"/>"#);
109    /// ```
110    pub fn float_formatter(mut self, formatter: FloatFormatter) -> Self {
111        self.float_formatter = Some(formatter);
112        self
113    }
114}
115
116/// Well-known XML namespace URIs and their conventional prefixes.
117const WELL_KNOWN_NAMESPACES: &[(&str, &str)] = &[
118    ("http://www.w3.org/2001/XMLSchema-instance", "xsi"),
119    ("http://www.w3.org/2001/XMLSchema", "xs"),
120    ("http://www.w3.org/XML/1998/namespace", "xml"),
121    ("http://www.w3.org/1999/xlink", "xlink"),
122    ("http://www.w3.org/2000/svg", "svg"),
123    ("http://www.w3.org/1999/xhtml", "xhtml"),
124    ("http://schemas.xmlsoap.org/soap/envelope/", "soap"),
125    ("http://www.w3.org/2003/05/soap-envelope", "soap12"),
126    ("http://schemas.android.com/apk/res/android", "android"),
127];
128
129pub(crate) type Result<T> = std::result::Result<T, XmlError>;
130
131/// Serialize a value of type `T` to an XML string.
132///
133/// The type `T` must be a struct where fields are marked with XML attributes like
134/// `#[facet(xml::element)]`, `#[facet(xml::attribute)]`, or `#[facet(xml::text)]`.
135///
136/// # Example
137/// ```
138/// # use facet::Facet;
139/// # use facet_xml as xml;
140/// # use facet_xml::to_string;
141/// #[derive(Facet)]
142/// struct Person {
143///     #[facet(xml::attribute)]
144///     id: u32,
145///     #[facet(xml::element)]
146///     name: String,
147/// }
148///
149/// # fn main() -> Result<(), facet_xml::XmlError> {
150/// let person = Person { id: 42, name: "Alice".into() };
151/// let xml = to_string(&person)?;
152/// assert_eq!(xml, r#"<Person id="42"><name>Alice</name></Person>"#);
153/// # Ok(())
154/// # }
155/// ```
156pub fn to_string<T: Facet<'static>>(value: &T) -> Result<String> {
157    to_string_with_options(value, &SerializeOptions::default())
158}
159
160/// Serialize a value of type `T` to a pretty-printed XML string.
161///
162/// This is a convenience function that enables pretty-printing with default indentation.
163///
164/// # Example
165/// ```
166/// # use facet::Facet;
167/// # use facet_xml as xml;
168/// # use facet_xml::to_string_pretty;
169/// #[derive(Facet)]
170/// struct Person {
171///     #[facet(xml::attribute)]
172///     id: u32,
173///     #[facet(xml::element)]
174///     name: String,
175/// }
176///
177/// # fn main() -> Result<(), facet_xml::XmlError> {
178/// let person = Person { id: 42, name: "Alice".into() };
179/// let xml = to_string_pretty(&person)?;
180/// // Output will have newlines and indentation
181/// # Ok(())
182/// # }
183/// ```
184pub fn to_string_pretty<T: Facet<'static>>(value: &T) -> Result<String> {
185    to_string_with_options(value, &SerializeOptions::default().pretty())
186}
187
188/// Serialize a value of type `T` to an XML string with custom options.
189///
190/// # Example
191///
192/// ```
193/// # use facet::Facet;
194/// # use facet_xml as xml;
195/// # use facet_xml::{to_string_with_options, SerializeOptions};
196/// #[derive(Facet)]
197/// struct Person {
198///     #[facet(xml::attribute)]
199///     id: u32,
200///     #[facet(xml::element)]
201///     name: String,
202/// }
203///
204/// # fn main() -> Result<(), facet_xml::XmlError> {
205/// let person = Person { id: 42, name: "Alice".into() };
206///
207/// // Compact output
208/// let xml = to_string_with_options(&person, &SerializeOptions::default())?;
209/// assert_eq!(xml, r#"<Person id="42"><name>Alice</name></Person>"#);
210///
211/// // Pretty output with tabs
212/// let xml = to_string_with_options(&person, &SerializeOptions::default().indent("\t"))?;
213/// # Ok(())
214/// # }
215/// ```
216pub fn to_string_with_options<T: Facet<'static>>(
217    value: &T,
218    options: &SerializeOptions,
219) -> Result<String> {
220    let mut output = Vec::new();
221    to_writer_with_options(&mut output, value, options)?;
222    Ok(String::from_utf8(output).expect("XML output should be valid UTF-8"))
223}
224
225/// Serialize a value of type `T` to a writer as XML.
226///
227/// This is the streaming version of [`to_string`] - it writes directly to any
228/// type implementing [`std::io::Write`].
229///
230/// # Example
231///
232/// Writing to a `Vec<u8>` buffer:
233/// ```
234/// # use facet::Facet;
235/// # use facet_xml as xml;
236/// # use facet_xml::to_writer;
237/// #[derive(Facet)]
238/// struct Person {
239///     #[facet(xml::attribute)]
240///     id: u32,
241///     #[facet(xml::element)]
242///     name: String,
243/// }
244///
245/// # fn main() -> Result<(), facet_xml::XmlError> {
246/// let person = Person { id: 42, name: "Alice".into() };
247/// let mut buffer = Vec::new();
248/// to_writer(&mut buffer, &person)?;
249/// let xml = String::from_utf8(buffer).unwrap();
250/// assert_eq!(xml, r#"<Person id="42"><name>Alice</name></Person>"#);
251/// # Ok(())
252/// # }
253/// ```
254pub fn to_writer<W: Write, T: Facet<'static>>(writer: &mut W, value: &T) -> Result<()> {
255    to_writer_with_options(writer, value, &SerializeOptions::default())
256}
257
258/// Serialize a value of type `T` to a writer as pretty-printed XML.
259///
260/// This is a convenience function that enables pretty-printing with default indentation.
261///
262/// # Example
263///
264/// ```
265/// # use facet::Facet;
266/// # use facet_xml as xml;
267/// # use facet_xml::to_writer_pretty;
268/// #[derive(Facet)]
269/// struct Person {
270///     #[facet(xml::attribute)]
271///     id: u32,
272///     #[facet(xml::element)]
273///     name: String,
274/// }
275///
276/// # fn main() -> Result<(), facet_xml::XmlError> {
277/// let person = Person { id: 42, name: "Alice".into() };
278/// let mut buffer = Vec::new();
279/// to_writer_pretty(&mut buffer, &person)?;
280/// // Output will have newlines and indentation
281/// # Ok(())
282/// # }
283/// ```
284pub fn to_writer_pretty<W: Write, T: Facet<'static>>(writer: &mut W, value: &T) -> Result<()> {
285    to_writer_with_options(writer, value, &SerializeOptions::default().pretty())
286}
287
288/// Serialize a value of type `T` to a writer as XML with custom options.
289///
290/// # Example
291///
292/// ```
293/// # use facet::Facet;
294/// # use facet_xml as xml;
295/// # use facet_xml::{to_writer_with_options, SerializeOptions};
296/// #[derive(Facet)]
297/// struct Person {
298///     #[facet(xml::attribute)]
299///     id: u32,
300///     #[facet(xml::element)]
301///     name: String,
302/// }
303///
304/// # fn main() -> Result<(), facet_xml::XmlError> {
305/// let person = Person { id: 42, name: "Alice".into() };
306///
307/// // Compact output (default)
308/// let mut buffer = Vec::new();
309/// to_writer_with_options(&mut buffer, &person, &SerializeOptions::default())?;
310/// assert_eq!(buffer, br#"<Person id="42"><name>Alice</name></Person>"#);
311///
312/// // Pretty output with default indent
313/// let mut buffer = Vec::new();
314/// to_writer_with_options(&mut buffer, &person, &SerializeOptions::default().pretty())?;
315///
316/// // Pretty output with custom indent (tabs)
317/// let mut buffer = Vec::new();
318/// to_writer_with_options(&mut buffer, &person, &SerializeOptions::default().indent("\t"))?;
319/// # Ok(())
320/// # }
321/// ```
322pub fn to_writer_with_options<W: Write, T: Facet<'static>>(
323    writer: &mut W,
324    value: &T,
325    options: &SerializeOptions,
326) -> Result<()> {
327    let peek = Peek::new(value);
328    let mut serializer = XmlSerializer::new(writer, options.indent_str(), options.float_formatter);
329
330    // Get the type name for the root element, respecting `rename` attribute
331    let type_name = crate::deserialize::get_shape_display_name(peek.shape());
332    serializer.serialize_element(type_name, peek)
333}
334
335struct XmlSerializer<'a, W> {
336    writer: W,
337    /// Namespace URI -> prefix mapping for already-declared namespaces.
338    declared_namespaces: HashMap<String, String>,
339    /// Counter for auto-generating namespace prefixes (ns0, ns1, ...).
340    next_ns_index: usize,
341    /// Indentation string for pretty-printing (None for compact output).
342    indent: Option<&'a str>,
343    /// Current indentation depth.
344    depth: usize,
345    /// The currently active default namespace (from xmlns="..." on an ancestor).
346    /// Child elements in this namespace don't need to re-declare it.
347    current_default_ns: Option<String>,
348    /// Custom formatter for floating-point numbers.
349    float_formatter: Option<FloatFormatter>,
350}
351
352impl<'a, W: Write> XmlSerializer<'a, W> {
353    fn new(writer: W, indent: Option<&'a str>, float_formatter: Option<FloatFormatter>) -> Self {
354        Self {
355            writer,
356            declared_namespaces: HashMap::new(),
357            next_ns_index: 0,
358            indent,
359            depth: 0,
360            current_default_ns: None,
361            float_formatter,
362        }
363    }
364
365    /// Write indentation for the current depth.
366    fn write_indent(&mut self) -> Result<()> {
367        if let Some(indent_str) = self.indent {
368            for _ in 0..self.depth {
369                self.writer
370                    .write_all(indent_str.as_bytes())
371                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
372            }
373        }
374        Ok(())
375    }
376
377    /// Write a newline if pretty-printing is enabled.
378    fn write_newline(&mut self) -> Result<()> {
379        if self.indent.is_some() {
380            self.writer
381                .write_all(b"\n")
382                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
383        }
384        Ok(())
385    }
386
387    /// Get or create a prefix for the given namespace URI.
388    /// Returns the prefix (without colon).
389    ///
390    /// Note: We always need to emit xmlns declarations on each element that uses a prefix,
391    /// because XML namespace declarations are scoped to the element and its descendants.
392    /// A declaration on a sibling or earlier element doesn't apply.
393    fn get_or_create_prefix(&mut self, namespace_uri: &str) -> String {
394        // Check if we've already assigned a prefix to this URI
395        if let Some(prefix) = self.declared_namespaces.get(namespace_uri) {
396            return prefix.clone();
397        }
398
399        // Try well-known namespaces
400        let prefix = WELL_KNOWN_NAMESPACES
401            .iter()
402            .find(|(uri, _)| *uri == namespace_uri)
403            .map(|(_, prefix)| (*prefix).to_string())
404            .unwrap_or_else(|| {
405                // Auto-generate a prefix
406                let prefix = format!("ns{}", self.next_ns_index);
407                self.next_ns_index += 1;
408                prefix
409            });
410
411        // Ensure the prefix isn't already in use for a different namespace
412        let final_prefix = if self.declared_namespaces.values().any(|p| p == &prefix) {
413            // Conflict! Generate a new one
414            let prefix = format!("ns{}", self.next_ns_index);
415            self.next_ns_index += 1;
416            prefix
417        } else {
418            prefix
419        };
420
421        self.declared_namespaces
422            .insert(namespace_uri.to_string(), final_prefix.clone());
423        final_prefix
424    }
425
426    /// Get the effective namespace for a field, considering field-level xml::ns
427    /// and container-level xml::ns_all.
428    ///
429    /// For attributes: `ns_all` is NOT applied because unprefixed attributes in XML
430    /// are always in "no namespace", regardless of any default xmlns declaration.
431    /// Only explicit `xml::ns` on the attribute field is used.
432    ///
433    /// For elements: Both `xml::ns` and `ns_all` are considered.
434    fn get_field_namespace(
435        field: &Field,
436        ns_all: Option<&'static str>,
437        is_attribute: bool,
438    ) -> Option<&'static str> {
439        if is_attribute {
440            // Attributes only use explicit xml::ns, not ns_all
441            // Per XML spec: unprefixed attributes are in "no namespace"
442            field.xml_ns()
443        } else {
444            // Elements use xml::ns or fall back to ns_all
445            field.xml_ns().or(ns_all)
446        }
447    }
448
449    fn serialize_element<'mem, 'facet>(
450        &mut self,
451        element_name: &str,
452        peek: Peek<'mem, 'facet>,
453    ) -> Result<()> {
454        // Handle Option<T> - skip if None
455        if let Ok(opt_peek) = peek.into_option() {
456            if opt_peek.is_none() {
457                return Ok(());
458            }
459            if let Some(inner) = opt_peek.value() {
460                return self.serialize_element(element_name, inner);
461            }
462            return Ok(());
463        }
464
465        // Handle Spanned<T> - unwrap to the inner value
466        if is_spanned_shape(peek.shape())
467            && let Ok(struct_peek) = peek.into_struct()
468            && let Ok(value_field) = struct_peek.field_by_name("value")
469        {
470            return self.serialize_element(element_name, value_field);
471        }
472
473        // Check if this is a struct
474        let shape = peek.shape();
475        if let Ok(struct_peek) = peek.into_struct() {
476            return self.serialize_struct_as_element(element_name, struct_peek, shape);
477        }
478
479        // Check if this is an enum
480        if let Ok(enum_peek) = peek.into_enum() {
481            return self.serialize_enum_as_element(element_name, enum_peek);
482        }
483
484        // Check if this is a byte slice/array - serialize as base64
485        if self.try_serialize_bytes_as_element(element_name, peek)? {
486            return Ok(());
487        }
488
489        // Check if this is a list-like type (Vec, array, set)
490        if let Ok(list_peek) = peek.into_list_like() {
491            return self.serialize_list_as_element(element_name, list_peek);
492        }
493
494        // Check if this is a map
495        if let Ok(map_peek) = peek.into_map() {
496            return self.serialize_map_as_element(element_name, map_peek);
497        }
498
499        // For scalars/primitives, serialize as element with text content
500        write!(self.writer, "<{}>", escape_element_name(element_name))
501            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
502        self.serialize_value(peek)?;
503        write!(self.writer, "</{}>", escape_element_name(element_name))
504            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
505
506        Ok(())
507    }
508
509    fn serialize_enum_as_element<'mem, 'facet>(
510        &mut self,
511        element_name: &str,
512        enum_peek: facet_reflect::PeekEnum<'mem, 'facet>,
513    ) -> Result<()> {
514        let shape = enum_peek.shape();
515        let variant_name = enum_peek
516            .variant_name_active()
517            .map_err(|_| XmlErrorKind::SerializeUnknownElementType)?;
518
519        let fields: Vec<_> = enum_peek.fields_for_serialize().collect();
520
521        // Determine enum tagging strategy
522        let is_untagged = shape.is_untagged();
523        let tag_attr = shape.get_tag_attr();
524        let content_attr = shape.get_content_attr();
525
526        if is_untagged {
527            // Untagged: serialize content directly with element name
528            self.serialize_enum_content(element_name, variant_name, &fields)?;
529        } else if let Some(tag) = tag_attr {
530            if let Some(content) = content_attr {
531                // Adjacently tagged: <Element tag="Variant"><content>...</content></Element>
532                write!(
533                    self.writer,
534                    "<{} {}=\"{}\">",
535                    escape_element_name(element_name),
536                    escape_element_name(tag),
537                    escape_attribute_value(variant_name)
538                )
539                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
540
541                if !fields.is_empty() {
542                    // Wrap content in the content element
543                    write!(self.writer, "<{}>", escape_element_name(content))
544                        .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
545                    self.serialize_variant_fields(&fields)?;
546                    write!(self.writer, "</{}>", escape_element_name(content))
547                        .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
548                }
549
550                write!(self.writer, "</{}>", escape_element_name(element_name))
551                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
552            } else {
553                // Internally tagged: <Element tag="Variant">...fields...</Element>
554                write!(
555                    self.writer,
556                    "<{} {}=\"{}\">",
557                    escape_element_name(element_name),
558                    escape_element_name(tag),
559                    escape_attribute_value(variant_name)
560                )
561                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
562
563                // Serialize fields directly (not wrapped in variant element)
564                self.serialize_variant_fields(&fields)?;
565
566                write!(self.writer, "</{}>", escape_element_name(element_name))
567                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
568            }
569        } else {
570            // Externally tagged (default): <Element><Variant>...</Variant></Element>
571            write!(self.writer, "<{}>", escape_element_name(element_name))
572                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
573
574            if fields.is_empty() {
575                // Unit variant - just the variant name as an empty element
576                write!(self.writer, "<{}/>", escape_element_name(variant_name))
577                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
578            } else if fields.len() == 1 && fields[0].0.name.parse::<usize>().is_ok() {
579                // Newtype variant - serialize the inner value with variant name
580                self.serialize_element(variant_name, fields[0].1)?;
581            } else {
582                // Struct-like variant
583                write!(self.writer, "<{}>", escape_element_name(variant_name))
584                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
585
586                for (field_item, field_peek) in fields {
587                    self.serialize_element(field_item.name, field_peek)?;
588                }
589
590                write!(self.writer, "</{}>", escape_element_name(variant_name))
591                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
592            }
593
594            write!(self.writer, "</{}>", escape_element_name(element_name))
595                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
596        }
597
598        Ok(())
599    }
600
601    /// Serialize enum content for untagged enums
602    fn serialize_enum_content<'mem, 'facet>(
603        &mut self,
604        element_name: &str,
605        variant_name: &str,
606        fields: &[(facet_reflect::FieldItem, Peek<'mem, 'facet>)],
607    ) -> Result<()> {
608        if fields.is_empty() {
609            // Unit variant - empty element
610            write!(self.writer, "<{}/>", escape_element_name(element_name))
611                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
612        } else if fields.len() == 1 && fields[0].0.name.parse::<usize>().is_ok() {
613            // Newtype variant - serialize inner directly
614            self.serialize_element(element_name, fields[0].1)?;
615        } else {
616            // Struct-like variant - serialize as struct
617            write!(self.writer, "<{}>", escape_element_name(element_name))
618                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
619
620            for (field_item, field_peek) in fields {
621                // Use variant_name as hint for structs in untagged context
622                let _ = variant_name; // Available if needed for disambiguation
623                self.serialize_element(field_item.name, *field_peek)?;
624            }
625
626            write!(self.writer, "</{}>", escape_element_name(element_name))
627                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
628        }
629        Ok(())
630    }
631
632    /// Serialize variant fields without wrapper
633    fn serialize_variant_fields<'mem, 'facet>(
634        &mut self,
635        fields: &[(facet_reflect::FieldItem, Peek<'mem, 'facet>)],
636    ) -> Result<()> {
637        if fields.len() == 1 && fields[0].0.name.parse::<usize>().is_ok() {
638            // Single tuple field - serialize value directly
639            self.serialize_value(fields[0].1)?;
640        } else {
641            for (field_item, field_peek) in fields {
642                self.serialize_element(field_item.name, *field_peek)?;
643            }
644        }
645        Ok(())
646    }
647
648    fn serialize_list_as_element<'mem, 'facet>(
649        &mut self,
650        element_name: &str,
651        list_peek: facet_reflect::PeekListLike<'mem, 'facet>,
652    ) -> Result<()> {
653        write!(self.writer, "<{}>", escape_element_name(element_name))
654            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
655
656        let has_items = list_peek.iter().next().is_some();
657        if has_items {
658            self.depth += 1;
659        }
660
661        for item in list_peek.iter() {
662            self.write_newline()?;
663            self.write_indent()?;
664            self.serialize_list_item_element(item)?;
665        }
666
667        if has_items {
668            self.depth -= 1;
669            self.write_newline()?;
670            self.write_indent()?;
671        }
672
673        write!(self.writer, "</{}>", escape_element_name(element_name))
674            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
675
676        Ok(())
677    }
678
679    fn serialize_map_as_element<'mem, 'facet>(
680        &mut self,
681        element_name: &str,
682        map_peek: facet_reflect::PeekMap<'mem, 'facet>,
683    ) -> Result<()> {
684        write!(self.writer, "<{}>", escape_element_name(element_name))
685            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
686
687        let has_items = map_peek.iter().next().is_some();
688        if has_items {
689            self.depth += 1;
690        }
691
692        for (key, value) in map_peek.iter() {
693            self.write_newline()?;
694            self.write_indent()?;
695            // Use the key as the element name
696            if let Some(key_str) = key.as_str() {
697                self.serialize_element(key_str, value)?;
698            } else if let Some(key_val) = value_to_string(key, self.float_formatter) {
699                self.serialize_element(&key_val, value)?;
700            } else {
701                // Fallback: use "entry" as element name with key as text
702                write!(self.writer, "<entry>").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
703                self.serialize_value(key)?;
704                self.serialize_value(value)?;
705                write!(self.writer, "</entry>").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
706            }
707        }
708
709        if has_items {
710            self.depth -= 1;
711            self.write_newline()?;
712            self.write_indent()?;
713        }
714
715        write!(self.writer, "</{}>", escape_element_name(element_name))
716            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
717
718        Ok(())
719    }
720
721    /// Try to serialize bytes (`Vec<u8>`, `&[u8]`, `[u8; N]`) as base64-encoded element.
722    /// Returns Ok(true) if bytes were handled, Ok(false) if not bytes.
723    fn try_serialize_bytes_as_element<'mem, 'facet>(
724        &mut self,
725        element_name: &str,
726        peek: Peek<'mem, 'facet>,
727    ) -> Result<bool> {
728        let shape = peek.shape();
729
730        // Check for Vec<u8>
731        if let Def::List(ld) = &shape.def
732            && ld.t().is_type::<u8>()
733            && let Some(bytes) = peek.as_bytes()
734        {
735            let encoded = BASE64_STANDARD.encode(bytes);
736            write!(self.writer, "<{}>", escape_element_name(element_name))
737                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
738            write!(self.writer, "{}", escape_text(&encoded))
739                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
740            write!(self.writer, "</{}>", escape_element_name(element_name))
741                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
742            return Ok(true);
743        }
744
745        // Check for [u8; N]
746        if let Def::Array(ad) = &shape.def
747            && ad.t().is_type::<u8>()
748        {
749            // Collect bytes from the array
750            if let Ok(list_peek) = peek.into_list_like() {
751                let bytes: Vec<u8> = list_peek
752                    .iter()
753                    .filter_map(|p| p.get::<u8>().ok().copied())
754                    .collect();
755                let encoded = BASE64_STANDARD.encode(&bytes);
756                write!(self.writer, "<{}>", escape_element_name(element_name))
757                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
758                write!(self.writer, "{}", escape_text(&encoded))
759                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
760                write!(self.writer, "</{}>", escape_element_name(element_name))
761                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
762                return Ok(true);
763            }
764        }
765
766        // Check for &[u8]
767        if let Def::Slice(sd) = &shape.def
768            && sd.t().is_type::<u8>()
769            && let Some(bytes) = peek.as_bytes()
770        {
771            let encoded = BASE64_STANDARD.encode(bytes);
772            write!(self.writer, "<{}>", escape_element_name(element_name))
773                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
774            write!(self.writer, "{}", escape_text(&encoded))
775                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
776            write!(self.writer, "</{}>", escape_element_name(element_name))
777                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
778            return Ok(true);
779        }
780
781        Ok(false)
782    }
783
784    fn serialize_struct_as_element<'mem, 'facet>(
785        &mut self,
786        element_name: &str,
787        struct_peek: facet_reflect::PeekStruct<'mem, 'facet>,
788        shape: &'static Shape,
789    ) -> Result<()> {
790        let struct_ty = struct_peek.ty();
791
792        match struct_ty.kind {
793            StructKind::Unit => {
794                // Unit struct - just output empty element
795                write!(self.writer, "<{}/>", escape_element_name(element_name))
796                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
797                return Ok(());
798            }
799            StructKind::Tuple | StructKind::TupleStruct => {
800                // Tuple struct - serialize fields in order as child elements
801                let fields: Vec<_> = struct_peek.fields_for_serialize().collect();
802                if fields.is_empty() {
803                    write!(self.writer, "<{}/>", escape_element_name(element_name))
804                        .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
805                    return Ok(());
806                }
807
808                write!(self.writer, "<{}>", escape_element_name(element_name))
809                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
810
811                for (i, (_, field_peek)) in fields.into_iter().enumerate() {
812                    // Use indexed element names for tuple fields
813                    let field_name = format!("_{i}");
814                    self.serialize_element(&field_name, field_peek)?;
815                }
816
817                write!(self.writer, "</{}>", escape_element_name(element_name))
818                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
819                return Ok(());
820            }
821            StructKind::Struct => {
822                // Named struct - fall through to normal handling
823            }
824        }
825
826        let fields = struct_ty.fields;
827        let missing = fields_missing_xml_annotations(fields, XmlAnnotationPhase::Serialize);
828        if !missing.is_empty() {
829            let field_info = missing
830                .into_iter()
831                .map(|field| (field.name, field.shape().type_identifier))
832                .collect();
833            return Err(XmlError::new(XmlErrorKind::MissingXmlAnnotations {
834                type_name: shape.type_identifier,
835                phase: MissingAnnotationPhase::Serialize,
836                fields: field_info,
837            }));
838        }
839
840        // Get container-level namespace default
841        let ns_all = shape.xml_ns_all();
842
843        // Collect attributes (with field info for namespace), elements, and text content
844        struct AttrInfo<'a> {
845            name: &'a str,
846            value: String,
847            namespace: Option<&'static str>,
848        }
849        let mut attributes: Vec<AttrInfo> = Vec::new();
850        let mut elements: Vec<(facet_reflect::FieldItem, Peek<'mem, 'facet>)> = Vec::new();
851        let mut elements_list: Vec<Peek<'mem, 'facet>> = Vec::new();
852        let mut text_content: Option<Peek<'mem, 'facet>> = None;
853
854        for (field_item, field_peek) in struct_peek.fields_for_serialize() {
855            let field = &field_item.field;
856
857            // Handle custom serialization for attributes - get value immediately
858            if field.is_xml_attribute() {
859                let value = if field.proxy_convert_out_fn().is_some() {
860                    // Get the intermediate representation for serialization
861                    if let Ok(owned) = field_peek.custom_serialization(*field) {
862                        value_to_string(owned.as_peek(), self.float_formatter)
863                    } else {
864                        value_to_string(field_peek, self.float_formatter)
865                    }
866                } else {
867                    value_to_string(field_peek, self.float_formatter)
868                };
869                if let Some(value) = value {
870                    // Pass is_attribute=true so ns_all is NOT applied
871                    let namespace = Self::get_field_namespace(field, ns_all, true);
872                    attributes.push(AttrInfo {
873                        name: field_item.name,
874                        value,
875                        namespace,
876                    });
877                }
878            } else if field.is_xml_element() {
879                elements.push((field_item, field_peek));
880            } else if field.is_xml_elements() {
881                elements_list.push(field_peek);
882            } else if field.is_xml_text() {
883                text_content = Some(field_peek);
884            }
885        }
886
887        // Determine if we need content
888        let has_content =
889            !elements.is_empty() || !elements_list.is_empty() || text_content.is_some();
890
891        // Collect xmlns declarations needed for attributes on this element
892        // We always emit xmlns declarations on the element that uses them, because
893        // XML namespace scope is limited to an element and its descendants.
894        let mut xmlns_decls: Vec<(String, String)> = Vec::new(); // (prefix, uri)
895        let mut attr_prefixes: Vec<Option<String>> = Vec::new(); // prefix for each attribute
896
897        for attr in &attributes {
898            if let Some(ns_uri) = attr.namespace {
899                let prefix = self.get_or_create_prefix(ns_uri);
900                // Always emit xmlns declaration on this element
901                if !xmlns_decls.iter().any(|(_, u)| u == ns_uri) {
902                    xmlns_decls.push((prefix.clone(), ns_uri.to_string()));
903                }
904                attr_prefixes.push(Some(prefix));
905            } else {
906                attr_prefixes.push(None);
907            }
908        }
909
910        // Write opening tag
911        write!(self.writer, "<{}", escape_element_name(element_name))
912            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
913
914        // If ns_all is set and differs from the current default namespace,
915        // emit a default namespace declaration (xmlns="...").
916        // Child elements with the same namespace will be unprefixed and inherit it.
917        let emitting_new_default_ns = if let Some(ns_uri) = ns_all {
918            let dominated = self
919                .current_default_ns
920                .as_ref()
921                .is_some_and(|current| current == ns_uri);
922            if !dominated {
923                write!(self.writer, " xmlns=\"{}\"", escape_attribute_value(ns_uri))
924                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
925                true
926            } else {
927                false
928            }
929        } else {
930            false
931        };
932
933        // Write xmlns declarations for attributes (only for explicitly namespaced attributes)
934        for (prefix, uri) in &xmlns_decls {
935            write!(
936                self.writer,
937                " xmlns:{}=\"{}\"",
938                escape_element_name(prefix),
939                escape_attribute_value(uri)
940            )
941            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
942        }
943
944        // Write attributes (with prefix if namespaced)
945        for (attr, prefix) in attributes.iter().zip(attr_prefixes.iter()) {
946            let attr_name = if let Some(p) = prefix {
947                format!("{p}:{}", attr.name)
948            } else {
949                attr.name.to_string()
950            };
951            write!(
952                self.writer,
953                " {}=\"{}\"",
954                escape_element_name(&attr_name),
955                escape_attribute_value(&attr.value)
956            )
957            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
958        }
959
960        if !has_content {
961            // Self-closing tag
962            write!(self.writer, "/>").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
963            return Ok(());
964        }
965
966        write!(self.writer, ">").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
967
968        // Save and update the default namespace for children
969        let old_default_ns = if emitting_new_default_ns {
970            let old = self.current_default_ns.take();
971            self.current_default_ns = ns_all.map(|s| s.to_string());
972            old
973        } else {
974            None
975        };
976
977        // Write text content if present (no indentation for text content)
978        if let Some(text_peek) = text_content {
979            self.serialize_text_value(text_peek)?;
980        }
981
982        // Check if we have child elements (for indentation purposes)
983        let has_child_elements = !elements.is_empty() || !elements_list.is_empty();
984
985        // Write child elements (with namespace support)
986        // Pass ns_all as the default namespace so child elements with matching
987        // namespace use unprefixed form (they inherit the default xmlns).
988        if has_child_elements {
989            self.depth += 1;
990        }
991
992        for (field_item, field_peek) in elements {
993            // Pass is_attribute=false for elements
994            let field_ns = Self::get_field_namespace(&field_item.field, ns_all, false);
995
996            self.write_newline()?;
997            self.write_indent()?;
998
999            // Handle custom serialization for elements
1000            if field_item.field.proxy_convert_out_fn().is_some() {
1001                if let Ok(owned) = field_peek.custom_serialization(field_item.field) {
1002                    self.serialize_namespaced_element(
1003                        field_item.name,
1004                        owned.as_peek(),
1005                        field_ns,
1006                        ns_all,
1007                    )?;
1008                } else {
1009                    self.serialize_namespaced_element(
1010                        field_item.name,
1011                        field_peek,
1012                        field_ns,
1013                        ns_all,
1014                    )?;
1015                }
1016            } else {
1017                self.serialize_namespaced_element(field_item.name, field_peek, field_ns, ns_all)?;
1018            }
1019        }
1020
1021        // Write elements lists
1022        for field_peek in elements_list {
1023            self.serialize_elements_list(field_peek)?;
1024        }
1025
1026        if has_child_elements {
1027            self.depth -= 1;
1028            self.write_newline()?;
1029            self.write_indent()?;
1030        }
1031
1032        // Restore the old default namespace
1033        if emitting_new_default_ns {
1034            self.current_default_ns = old_default_ns;
1035        }
1036
1037        // Write closing tag
1038        write!(self.writer, "</{}>", escape_element_name(element_name))
1039            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1040
1041        Ok(())
1042    }
1043
1044    /// Serialize an element with optional namespace.
1045    ///
1046    /// - `namespace`: The namespace this element should be in
1047    /// - `default_ns`: The currently active default namespace (from parent's xmlns="...")
1048    ///
1049    /// If the element's namespace matches the default namespace, we use an unprefixed
1050    /// element name (the element inherits the default namespace).
1051    /// Otherwise, we use a prefix and emit an xmlns:prefix declaration.
1052    fn serialize_namespaced_element<'mem, 'facet>(
1053        &mut self,
1054        element_name: &str,
1055        peek: Peek<'mem, 'facet>,
1056        namespace: Option<&str>,
1057        default_ns: Option<&str>,
1058    ) -> Result<()> {
1059        // Handle Option<T> - skip if None
1060        if let Ok(opt_peek) = peek.into_option() {
1061            if opt_peek.is_none() {
1062                return Ok(());
1063            }
1064            if let Some(inner) = opt_peek.value() {
1065                return self.serialize_namespaced_element(
1066                    element_name,
1067                    inner,
1068                    namespace,
1069                    default_ns,
1070                );
1071            }
1072            return Ok(());
1073        }
1074
1075        // Handle Spanned<T> - unwrap to the inner value
1076        if is_spanned_shape(peek.shape())
1077            && let Ok(struct_peek) = peek.into_struct()
1078            && let Ok(value_field) = struct_peek.field_by_name("value")
1079        {
1080            return self.serialize_namespaced_element(
1081                element_name,
1082                value_field,
1083                namespace,
1084                default_ns,
1085            );
1086        }
1087
1088        // Determine element name and xmlns declaration
1089        // If namespace matches the current default, use unprefixed form (inherit default).
1090        // Otherwise, use a prefix and emit xmlns:prefix declaration.
1091        let (final_name, xmlns_decl) = if let Some(ns_uri) = namespace {
1092            if default_ns == Some(ns_uri) {
1093                // Element is in the default namespace - use unprefixed form
1094                (element_name.to_string(), None)
1095            } else {
1096                // Element is in a different namespace - use prefix
1097                let prefix = self.get_or_create_prefix(ns_uri);
1098                let prefixed = format!("{prefix}:{element_name}");
1099                (prefixed, Some((prefix, ns_uri.to_string())))
1100            }
1101        } else {
1102            (element_name.to_string(), None)
1103        };
1104
1105        // Check if this is a struct - handle specially for proper namespace propagation
1106        let shape = peek.shape();
1107        if let Ok(struct_peek) = peek.into_struct() {
1108            return self.serialize_struct_as_namespaced_element(
1109                &final_name,
1110                struct_peek,
1111                xmlns_decl,
1112                shape,
1113                default_ns,
1114            );
1115        }
1116
1117        // Check if this is an enum
1118        if let Ok(enum_peek) = peek.into_enum() {
1119            return self.serialize_enum_as_namespaced_element(&final_name, enum_peek, xmlns_decl);
1120        }
1121
1122        // For scalars/primitives, serialize as element with text content
1123        write!(self.writer, "<{}", escape_element_name(&final_name))
1124            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1125
1126        // Add xmlns declaration if needed
1127        if let Some((prefix, uri)) = xmlns_decl {
1128            write!(
1129                self.writer,
1130                " xmlns:{}=\"{}\"",
1131                escape_element_name(&prefix),
1132                escape_attribute_value(&uri)
1133            )
1134            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1135        }
1136
1137        write!(self.writer, ">").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1138        self.serialize_value(peek)?;
1139        write!(self.writer, "</{}>", escape_element_name(&final_name))
1140            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1141
1142        Ok(())
1143    }
1144
1145    /// Serialize a struct as an element with optional xmlns declaration on the opening tag.
1146    ///
1147    /// - `parent_default_ns`: The default namespace inherited from the parent element
1148    fn serialize_struct_as_namespaced_element<'mem, 'facet>(
1149        &mut self,
1150        element_name: &str,
1151        struct_peek: facet_reflect::PeekStruct<'mem, 'facet>,
1152        xmlns_decl: Option<(String, String)>,
1153        shape: &'static Shape,
1154        parent_default_ns: Option<&str>,
1155    ) -> Result<()> {
1156        match struct_peek.ty().kind {
1157            StructKind::Unit => {
1158                // Unit struct - just output empty element with xmlns if needed
1159                write!(self.writer, "<{}", escape_element_name(element_name))
1160                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1161                if let Some((prefix, uri)) = xmlns_decl {
1162                    write!(
1163                        self.writer,
1164                        " xmlns:{}=\"{}\"",
1165                        escape_element_name(&prefix),
1166                        escape_attribute_value(&uri)
1167                    )
1168                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1169                }
1170                write!(self.writer, "/>").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1171                return Ok(());
1172            }
1173            StructKind::Tuple | StructKind::TupleStruct => {
1174                // Tuple struct - serialize fields in order as child elements
1175                let fields: Vec<_> = struct_peek.fields_for_serialize().collect();
1176                if fields.is_empty() {
1177                    write!(self.writer, "<{}", escape_element_name(element_name))
1178                        .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1179                    if let Some((prefix, uri)) = xmlns_decl {
1180                        write!(
1181                            self.writer,
1182                            " xmlns:{}=\"{}\"",
1183                            escape_element_name(&prefix),
1184                            escape_attribute_value(&uri)
1185                        )
1186                        .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1187                    }
1188                    write!(self.writer, "/>").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1189                    return Ok(());
1190                }
1191
1192                write!(self.writer, "<{}", escape_element_name(element_name))
1193                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1194                if let Some((prefix, uri)) = xmlns_decl {
1195                    write!(
1196                        self.writer,
1197                        " xmlns:{}=\"{}\"",
1198                        escape_element_name(&prefix),
1199                        escape_attribute_value(&uri)
1200                    )
1201                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1202                }
1203                write!(self.writer, ">").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1204
1205                for (i, (_, field_peek)) in fields.into_iter().enumerate() {
1206                    let field_name = format!("_{i}");
1207                    self.serialize_element(&field_name, field_peek)?;
1208                }
1209
1210                write!(self.writer, "</{}>", escape_element_name(element_name))
1211                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1212                return Ok(());
1213            }
1214            StructKind::Struct => {
1215                // Named struct - fall through to normal handling
1216            }
1217        }
1218
1219        // Get container-level namespace default for the nested struct
1220        let ns_all = shape.xml_ns_all();
1221
1222        // The actual default namespace in the XML is inherited from parent.
1223        // We don't emit xmlns="..." on nested elements because that would
1224        // change the element's own namespace. Child elements in a different
1225        // namespace will use prefixed form.
1226        let effective_default_ns: Option<&str> = parent_default_ns;
1227
1228        // Collect attributes, elements, and text content
1229        struct AttrInfo<'a> {
1230            name: &'a str,
1231            value: String,
1232            namespace: Option<&'static str>,
1233        }
1234        let mut attributes: Vec<AttrInfo> = Vec::new();
1235        let mut elements: Vec<(facet_reflect::FieldItem, Peek<'mem, 'facet>)> = Vec::new();
1236        let mut elements_list: Vec<Peek<'mem, 'facet>> = Vec::new();
1237        let mut text_content: Option<Peek<'mem, 'facet>> = None;
1238
1239        for (field_item, field_peek) in struct_peek.fields_for_serialize() {
1240            let field = &field_item.field;
1241
1242            if field.is_xml_attribute() {
1243                let value = if field.proxy_convert_out_fn().is_some() {
1244                    if let Ok(owned) = field_peek.custom_serialization(*field) {
1245                        value_to_string(owned.as_peek(), self.float_formatter)
1246                    } else {
1247                        value_to_string(field_peek, self.float_formatter)
1248                    }
1249                } else {
1250                    value_to_string(field_peek, self.float_formatter)
1251                };
1252                if let Some(value) = value {
1253                    // Pass is_attribute=true so ns_all is NOT applied
1254                    let namespace = Self::get_field_namespace(field, ns_all, true);
1255                    attributes.push(AttrInfo {
1256                        name: field_item.name,
1257                        value,
1258                        namespace,
1259                    });
1260                }
1261            } else if field.is_xml_element() {
1262                elements.push((field_item, field_peek));
1263            } else if field.is_xml_elements() {
1264                elements_list.push(field_peek);
1265            } else if field.is_xml_text() {
1266                text_content = Some(field_peek);
1267            }
1268        }
1269
1270        let has_content =
1271            !elements.is_empty() || !elements_list.is_empty() || text_content.is_some();
1272
1273        // Collect xmlns declarations needed for attributes
1274        // We always emit xmlns declarations on each element that uses them.
1275        let mut xmlns_decls: Vec<(String, String)> = Vec::new();
1276        let mut attr_prefixes: Vec<Option<String>> = Vec::new();
1277
1278        // Start with the element's own xmlns declaration if any (from prefixed form)
1279        if let Some((prefix, uri)) = xmlns_decl {
1280            xmlns_decls.push((prefix, uri));
1281        }
1282
1283        for attr in &attributes {
1284            if let Some(ns_uri) = attr.namespace {
1285                let prefix = self.get_or_create_prefix(ns_uri);
1286                // Always emit xmlns declaration on this element (if not already)
1287                if !xmlns_decls.iter().any(|(_, u)| u == ns_uri) {
1288                    xmlns_decls.push((prefix.clone(), ns_uri.to_string()));
1289                }
1290                attr_prefixes.push(Some(prefix));
1291            } else {
1292                attr_prefixes.push(None);
1293            }
1294        }
1295
1296        // Write opening tag
1297        write!(self.writer, "<{}", escape_element_name(element_name))
1298            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1299
1300        // NOTE: We intentionally do NOT emit xmlns="..." on nested struct elements here.
1301        // The element itself is in the parent's namespace (determined by the context
1302        // where it's used). Only the struct's CHILD elements are affected by ns_all.
1303        // Child elements in a different namespace will use prefixed form.
1304
1305        // Write prefixed xmlns declarations (for explicitly namespaced attributes)
1306        for (prefix, uri) in &xmlns_decls {
1307            write!(
1308                self.writer,
1309                " xmlns:{}=\"{}\"",
1310                escape_element_name(prefix),
1311                escape_attribute_value(uri)
1312            )
1313            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1314        }
1315
1316        // Write attributes
1317        for (attr, prefix) in attributes.iter().zip(attr_prefixes.iter()) {
1318            let attr_name = if let Some(p) = prefix {
1319                format!("{p}:{}", attr.name)
1320            } else {
1321                attr.name.to_string()
1322            };
1323            write!(
1324                self.writer,
1325                " {}=\"{}\"",
1326                escape_element_name(&attr_name),
1327                escape_attribute_value(&attr.value)
1328            )
1329            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1330        }
1331
1332        if !has_content {
1333            write!(self.writer, "/>").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1334            return Ok(());
1335        }
1336
1337        write!(self.writer, ">").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1338
1339        if let Some(text_peek) = text_content {
1340            self.serialize_text_value(text_peek)?;
1341        }
1342
1343        // Check if we have child elements (for indentation purposes)
1344        let has_child_elements = !elements.is_empty() || !elements_list.is_empty();
1345
1346        if has_child_elements {
1347            self.depth += 1;
1348        }
1349
1350        for (field_item, field_peek) in elements {
1351            // Pass is_attribute=false for elements
1352            let field_ns = Self::get_field_namespace(&field_item.field, ns_all, false);
1353
1354            self.write_newline()?;
1355            self.write_indent()?;
1356
1357            if field_item.field.proxy_convert_out_fn().is_some() {
1358                if let Ok(owned) = field_peek.custom_serialization(field_item.field) {
1359                    self.serialize_namespaced_element(
1360                        field_item.name,
1361                        owned.as_peek(),
1362                        field_ns,
1363                        effective_default_ns,
1364                    )?;
1365                } else {
1366                    self.serialize_namespaced_element(
1367                        field_item.name,
1368                        field_peek,
1369                        field_ns,
1370                        effective_default_ns,
1371                    )?;
1372                }
1373            } else {
1374                self.serialize_namespaced_element(
1375                    field_item.name,
1376                    field_peek,
1377                    field_ns,
1378                    effective_default_ns,
1379                )?;
1380            }
1381        }
1382
1383        for field_peek in elements_list {
1384            self.serialize_elements_list(field_peek)?;
1385        }
1386
1387        if has_child_elements {
1388            self.depth -= 1;
1389            self.write_newline()?;
1390            self.write_indent()?;
1391        }
1392
1393        write!(self.writer, "</{}>", escape_element_name(element_name))
1394            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1395
1396        Ok(())
1397    }
1398
1399    /// Serialize an enum as an element with optional xmlns declaration.
1400    fn serialize_enum_as_namespaced_element<'mem, 'facet>(
1401        &mut self,
1402        prefixed_element_name: &str,
1403        enum_peek: facet_reflect::PeekEnum<'mem, 'facet>,
1404        xmlns_decl: Option<(String, String)>,
1405    ) -> Result<()> {
1406        let shape = enum_peek.shape();
1407        let variant_name = enum_peek
1408            .variant_name_active()
1409            .map_err(|_| XmlErrorKind::SerializeUnknownElementType)?;
1410
1411        let fields: Vec<_> = enum_peek.fields_for_serialize().collect();
1412
1413        let is_untagged = shape.is_untagged();
1414        let tag_attr = shape.get_tag_attr();
1415        let content_attr = shape.get_content_attr();
1416
1417        // Helper to write opening tag with optional xmlns
1418        let write_open_tag =
1419            |writer: &mut W, name: &str, xmlns: &Option<(String, String)>| -> Result<()> {
1420                write!(writer, "<{}", escape_element_name(name))
1421                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1422                if let Some((prefix, uri)) = xmlns {
1423                    write!(
1424                        writer,
1425                        " xmlns:{}=\"{}\"",
1426                        escape_element_name(prefix),
1427                        escape_attribute_value(uri)
1428                    )
1429                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1430                }
1431                Ok(())
1432            };
1433
1434        if is_untagged {
1435            // Untagged: serialize content directly
1436            if fields.is_empty() {
1437                write_open_tag(&mut self.writer, prefixed_element_name, &xmlns_decl)?;
1438                write!(self.writer, "/>").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1439            } else if fields.len() == 1 && fields[0].0.name.parse::<usize>().is_ok() {
1440                // Newtype variant
1441                write_open_tag(&mut self.writer, prefixed_element_name, &xmlns_decl)?;
1442                write!(self.writer, ">").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1443                self.serialize_value(fields[0].1)?;
1444                write!(
1445                    self.writer,
1446                    "</{}>",
1447                    escape_element_name(prefixed_element_name)
1448                )
1449                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1450            } else {
1451                write_open_tag(&mut self.writer, prefixed_element_name, &xmlns_decl)?;
1452                write!(self.writer, ">").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1453                for (field_item, field_peek) in fields {
1454                    self.serialize_element(field_item.name, field_peek)?;
1455                }
1456                write!(
1457                    self.writer,
1458                    "</{}>",
1459                    escape_element_name(prefixed_element_name)
1460                )
1461                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1462            }
1463        } else if let Some(tag) = tag_attr {
1464            if let Some(content) = content_attr {
1465                // Adjacently tagged
1466                write_open_tag(&mut self.writer, prefixed_element_name, &xmlns_decl)?;
1467                write!(
1468                    self.writer,
1469                    " {}=\"{}\">",
1470                    escape_element_name(tag),
1471                    escape_attribute_value(variant_name)
1472                )
1473                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1474
1475                if !fields.is_empty() {
1476                    write!(self.writer, "<{}>", escape_element_name(content))
1477                        .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1478                    self.serialize_variant_fields(&fields)?;
1479                    write!(self.writer, "</{}>", escape_element_name(content))
1480                        .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1481                }
1482
1483                write!(
1484                    self.writer,
1485                    "</{}>",
1486                    escape_element_name(prefixed_element_name)
1487                )
1488                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1489            } else {
1490                // Internally tagged
1491                write_open_tag(&mut self.writer, prefixed_element_name, &xmlns_decl)?;
1492                write!(
1493                    self.writer,
1494                    " {}=\"{}\">",
1495                    escape_element_name(tag),
1496                    escape_attribute_value(variant_name)
1497                )
1498                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1499                self.serialize_variant_fields(&fields)?;
1500                write!(
1501                    self.writer,
1502                    "</{}>",
1503                    escape_element_name(prefixed_element_name)
1504                )
1505                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1506            }
1507        } else {
1508            // Externally tagged (default)
1509            write_open_tag(&mut self.writer, prefixed_element_name, &xmlns_decl)?;
1510            write!(self.writer, ">").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1511
1512            if fields.is_empty() {
1513                write!(self.writer, "<{}/>", escape_element_name(variant_name))
1514                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1515            } else if fields.len() == 1 && fields[0].0.name.parse::<usize>().is_ok() {
1516                self.serialize_element(variant_name, fields[0].1)?;
1517            } else {
1518                write!(self.writer, "<{}>", escape_element_name(variant_name))
1519                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1520                for (field_item, field_peek) in fields {
1521                    self.serialize_element(field_item.name, field_peek)?;
1522                }
1523                write!(self.writer, "</{}>", escape_element_name(variant_name))
1524                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1525            }
1526
1527            write!(
1528                self.writer,
1529                "</{}>",
1530                escape_element_name(prefixed_element_name)
1531            )
1532            .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1533        }
1534
1535        Ok(())
1536    }
1537
1538    fn serialize_elements_list<'mem, 'facet>(&mut self, peek: Peek<'mem, 'facet>) -> Result<()> {
1539        let list_peek = peek
1540            .into_list()
1541            .map_err(|_| XmlErrorKind::SerializeNotList)?;
1542
1543        for item_peek in list_peek.iter() {
1544            self.write_newline()?;
1545            self.write_indent()?;
1546            self.serialize_list_item_element(item_peek)?;
1547        }
1548
1549        Ok(())
1550    }
1551
1552    fn serialize_list_item_element<'mem, 'facet>(
1553        &mut self,
1554        peek: Peek<'mem, 'facet>,
1555    ) -> Result<()> {
1556        // For enums, use variant name as element name
1557        if let Ok(enum_peek) = peek.into_enum() {
1558            let variant_name = enum_peek
1559                .variant_name_active()
1560                .map_err(|_| XmlErrorKind::SerializeUnknownElementType)?;
1561
1562            // Get the variant's fields (respecting skip_serializing)
1563            let fields: Vec<_> = enum_peek.fields_for_serialize().collect();
1564
1565            if fields.is_empty() {
1566                // Unit variant - empty element
1567                write!(self.writer, "<{}/>", escape_element_name(variant_name))
1568                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1569            } else if fields.len() == 1 && fields[0].0.name.parse::<usize>().is_ok() {
1570                // Tuple variant with single field - serialize the inner value
1571                self.serialize_element(variant_name, fields[0].1)?;
1572            } else {
1573                // Struct-like variant
1574                write!(self.writer, "<{}>", escape_element_name(variant_name))
1575                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1576
1577                for (field_item, field_peek) in fields {
1578                    self.serialize_element(field_item.name, field_peek)?;
1579                }
1580
1581                write!(self.writer, "</{}>", escape_element_name(variant_name))
1582                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1583            }
1584            return Ok(());
1585        }
1586
1587        // For structs, use type name as element name
1588        let type_name = peek.shape().type_identifier;
1589        self.serialize_element(type_name, peek)
1590    }
1591
1592    fn serialize_text_value<'mem, 'facet>(&mut self, peek: Peek<'mem, 'facet>) -> Result<()> {
1593        // Handle Option<T>
1594        if let Ok(opt_peek) = peek.into_option() {
1595            if opt_peek.is_none() {
1596                return Ok(());
1597            }
1598            if let Some(inner) = opt_peek.value() {
1599                return self.serialize_text_value(inner);
1600            }
1601            return Ok(());
1602        }
1603
1604        // Handle Spanned<T>
1605        if is_spanned_shape(peek.shape())
1606            && let Ok(struct_peek) = peek.into_struct()
1607            && let Ok(value_peek) = struct_peek.field_by_name("value")
1608        {
1609            return self.serialize_text_value(value_peek);
1610        }
1611
1612        self.serialize_value(peek)
1613    }
1614
1615    fn serialize_value<'mem, 'facet>(&mut self, peek: Peek<'mem, 'facet>) -> Result<()> {
1616        // Handle Option<T>
1617        if let Ok(opt_peek) = peek.into_option() {
1618            if opt_peek.is_none() {
1619                return Ok(());
1620            }
1621            if let Some(inner) = opt_peek.value() {
1622                return self.serialize_value(inner);
1623            }
1624            return Ok(());
1625        }
1626
1627        // Handle Spanned<T>
1628        if is_spanned_shape(peek.shape())
1629            && let Ok(struct_peek) = peek.into_struct()
1630            && let Ok(value_peek) = struct_peek.field_by_name("value")
1631        {
1632            return self.serialize_value(value_peek);
1633        }
1634
1635        // Unwrap transparent wrappers
1636        let peek = peek.innermost_peek();
1637
1638        // Try string first
1639        if let Some(s) = peek.as_str() {
1640            write!(self.writer, "{}", escape_text(s))
1641                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1642            return Ok(());
1643        }
1644
1645        // Try various types
1646        if let Ok(v) = peek.get::<bool>() {
1647            write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1648            return Ok(());
1649        }
1650
1651        if let Ok(v) = peek.get::<i8>() {
1652            write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1653            return Ok(());
1654        }
1655        if let Ok(v) = peek.get::<i16>() {
1656            write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1657            return Ok(());
1658        }
1659        if let Ok(v) = peek.get::<i32>() {
1660            write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1661            return Ok(());
1662        }
1663        if let Ok(v) = peek.get::<i64>() {
1664            write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1665            return Ok(());
1666        }
1667
1668        if let Ok(v) = peek.get::<u8>() {
1669            write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1670            return Ok(());
1671        }
1672        if let Ok(v) = peek.get::<u16>() {
1673            write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1674            return Ok(());
1675        }
1676        if let Ok(v) = peek.get::<u32>() {
1677            write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1678            return Ok(());
1679        }
1680        if let Ok(v) = peek.get::<u64>() {
1681            write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1682            return Ok(());
1683        }
1684
1685        if let Ok(v) = peek.get::<f32>() {
1686            if let Some(fmt) = self.float_formatter {
1687                fmt(f64::from(*v), &mut self.writer)
1688                    .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1689            } else {
1690                write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1691            }
1692            return Ok(());
1693        }
1694        if let Ok(v) = peek.get::<f64>() {
1695            if let Some(fmt) = self.float_formatter {
1696                fmt(*v, &mut self.writer).map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1697            } else {
1698                write!(self.writer, "{v}").map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1699            }
1700            return Ok(());
1701        }
1702
1703        if let Ok(v) = peek.get::<char>() {
1704            write!(self.writer, "{}", escape_text(&v.to_string()))
1705                .map_err(|e| XmlErrorKind::Io(e.to_string()))?;
1706            return Ok(());
1707        }
1708
1709        Err(XmlErrorKind::SerializeUnknownValueType.into())
1710    }
1711}
1712
1713/// Convert a Peek value to a string representation, handling Options, Spanned, and transparent wrappers.
1714fn value_to_string<'mem, 'facet>(
1715    peek: Peek<'mem, 'facet>,
1716    float_formatter: Option<FloatFormatter>,
1717) -> Option<String> {
1718    // Handle Option<T>
1719    if let Ok(opt_peek) = peek.into_option() {
1720        if opt_peek.is_none() {
1721            return None;
1722        }
1723        if let Some(inner) = opt_peek.value() {
1724            return value_to_string(inner, float_formatter);
1725        }
1726        return None;
1727    }
1728
1729    // Handle Spanned<T>
1730    if is_spanned_shape(peek.shape())
1731        && let Ok(struct_peek) = peek.into_struct()
1732        && let Ok(value_peek) = struct_peek.field_by_name("value")
1733    {
1734        return value_to_string(value_peek, float_formatter);
1735    }
1736
1737    // Unwrap transparent wrappers
1738    let peek = peek.innermost_peek();
1739
1740    // Try string first
1741    if let Some(s) = peek.as_str() {
1742        return Some(s.to_string());
1743    }
1744
1745    // Try various types
1746    if let Ok(v) = peek.get::<bool>() {
1747        return Some(v.to_string());
1748    }
1749
1750    if let Ok(v) = peek.get::<i8>() {
1751        return Some(v.to_string());
1752    }
1753    if let Ok(v) = peek.get::<i16>() {
1754        return Some(v.to_string());
1755    }
1756    if let Ok(v) = peek.get::<i32>() {
1757        return Some(v.to_string());
1758    }
1759    if let Ok(v) = peek.get::<i64>() {
1760        return Some(v.to_string());
1761    }
1762
1763    if let Ok(v) = peek.get::<u8>() {
1764        return Some(v.to_string());
1765    }
1766    if let Ok(v) = peek.get::<u16>() {
1767        return Some(v.to_string());
1768    }
1769    if let Ok(v) = peek.get::<u32>() {
1770        return Some(v.to_string());
1771    }
1772    if let Ok(v) = peek.get::<u64>() {
1773        return Some(v.to_string());
1774    }
1775
1776    if let Ok(v) = peek.get::<f32>() {
1777        if let Some(fmt) = float_formatter {
1778            let mut buf = Vec::new();
1779            if fmt(f64::from(*v), &mut buf).is_ok() {
1780                return String::from_utf8(buf).ok();
1781            }
1782        }
1783        return Some(v.to_string());
1784    }
1785    if let Ok(v) = peek.get::<f64>() {
1786        if let Some(fmt) = float_formatter {
1787            let mut buf = Vec::new();
1788            if fmt(*v, &mut buf).is_ok() {
1789                return String::from_utf8(buf).ok();
1790            }
1791        }
1792        return Some(v.to_string());
1793    }
1794
1795    if let Ok(v) = peek.get::<char>() {
1796        return Some(v.to_string());
1797    }
1798
1799    None
1800}
1801
1802/// Escape special characters in XML text content.
1803fn escape_text(s: &str) -> String {
1804    let mut result = String::with_capacity(s.len());
1805    for c in s.chars() {
1806        match c {
1807            '<' => result.push_str("&lt;"),
1808            '>' => result.push_str("&gt;"),
1809            '&' => result.push_str("&amp;"),
1810            _ => result.push(c),
1811        }
1812    }
1813    result
1814}
1815
1816/// Escape special characters in XML attribute values.
1817fn escape_attribute_value(s: &str) -> String {
1818    let mut result = String::with_capacity(s.len());
1819    for c in s.chars() {
1820        match c {
1821            '<' => result.push_str("&lt;"),
1822            '>' => result.push_str("&gt;"),
1823            '&' => result.push_str("&amp;"),
1824            '"' => result.push_str("&quot;"),
1825            '\'' => result.push_str("&apos;"),
1826            _ => result.push(c),
1827        }
1828    }
1829    result
1830}
1831
1832/// Escape element name (for now, assume valid XML names).
1833fn escape_element_name(name: &str) -> &str {
1834    name
1835}