facet_format_xml/
serializer.rs

1extern crate alloc;
2
3use alloc::{format, string::String, vec::Vec};
4use std::collections::HashMap;
5
6use facet_core::Facet;
7use facet_format::{FormatSerializer, ScalarValue, SerializeError, serialize_root};
8use facet_reflect::Peek;
9
10/// Well-known XML namespace URIs and their conventional prefixes.
11#[allow(dead_code)] // Used in Phase 4 namespace serialization (partial implementation)
12const WELL_KNOWN_NAMESPACES: &[(&str, &str)] = &[
13    ("http://www.w3.org/2001/XMLSchema-instance", "xsi"),
14    ("http://www.w3.org/2001/XMLSchema", "xs"),
15    ("http://www.w3.org/XML/1998/namespace", "xml"),
16    ("http://www.w3.org/1999/xlink", "xlink"),
17    ("http://www.w3.org/2000/svg", "svg"),
18    ("http://www.w3.org/1999/xhtml", "xhtml"),
19    ("http://schemas.xmlsoap.org/soap/envelope/", "soap"),
20    ("http://www.w3.org/2003/05/soap-envelope", "soap12"),
21    ("http://schemas.android.com/apk/res/android", "android"),
22];
23
24#[derive(Debug)]
25pub struct XmlSerializeError {
26    msg: &'static str,
27}
28
29impl core::fmt::Display for XmlSerializeError {
30    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31        f.write_str(self.msg)
32    }
33}
34
35impl std::error::Error for XmlSerializeError {}
36
37#[derive(Debug)]
38enum Ctx {
39    Root { kind: Option<Kind> },
40    Struct { close: Option<String> },
41    Seq { close: Option<String> },
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45enum Kind {
46    Struct,
47    Seq,
48}
49
50/// Minimal XML serializer for the codex prototype.
51///
52/// The output is designed to round-trip through `facet-format-xml`'s parser:
53/// - structs are elements whose children are field elements
54/// - sequences are elements whose children are repeated `<item>` elements
55/// - element names are treated as map keys; the root element name is ignored
56pub struct XmlSerializer {
57    out: Vec<u8>,
58    stack: Vec<Ctx>,
59    pending_field: Option<String>,
60    /// Pending namespace for the next field to be serialized
61    pending_namespace: Option<String>,
62    /// True if the current field is an attribute (vs element)
63    pending_is_attribute: bool,
64    /// True if the current field is text content (xml::text)
65    pending_is_text: bool,
66    /// Container-level default namespace (from xml::ns_all) for current struct
67    current_ns_all: Option<String>,
68    /// Buffered attributes for the current element (name, value, namespace_opt)
69    pending_attributes: Vec<(String, String, Option<String>)>,
70    item_tag: &'static str,
71    /// Namespace URI -> prefix mapping for already-declared namespaces.
72    declared_namespaces: HashMap<String, String>,
73    /// Counter for auto-generating namespace prefixes (ns0, ns1, ...).
74    next_ns_index: usize,
75    /// The currently active default namespace (from xmlns="..." on an ancestor).
76    /// When set, elements in this namespace use unprefixed names.
77    current_default_ns: Option<String>,
78    /// True if we've written the opening `<root>` tag
79    root_tag_written: bool,
80    /// Deferred element tag - we wait to write the opening tag until we've collected all attributes.
81    /// Format: (element_name, namespace, close_name)
82    /// When Some, we haven't written `<tag ...>` yet; attributes are being collected in pending_attributes.
83    deferred_open_tag: Option<(String, Option<String>, String)>,
84}
85
86impl XmlSerializer {
87    pub fn new() -> Self {
88        Self {
89            out: Vec::new(),
90            stack: vec![Ctx::Root { kind: None }],
91            pending_field: None,
92            pending_namespace: None,
93            pending_is_attribute: false,
94            pending_is_text: false,
95            current_ns_all: None,
96            pending_attributes: Vec::new(),
97            item_tag: "item",
98            declared_namespaces: HashMap::new(),
99            next_ns_index: 0,
100            current_default_ns: None,
101            root_tag_written: false,
102            deferred_open_tag: None,
103        }
104    }
105
106    pub fn finish(mut self) -> Vec<u8> {
107        // Ensure root tag is written (even if struct is empty)
108        self.ensure_root_tag_written();
109
110        // Close any remaining non-root elements.
111        while let Some(ctx) = self.stack.pop() {
112            match ctx {
113                Ctx::Root { .. } => break,
114                Ctx::Struct { close } | Ctx::Seq { close } => {
115                    if let Some(name) = close {
116                        self.write_close_tag(&name);
117                    }
118                }
119            }
120        }
121        self.out.extend_from_slice(b"</root>");
122        self.out
123    }
124
125    /// Flush any deferred opening tag (writing `<tag attrs>`) before we need to write content.
126    /// This is called when we encounter a non-attribute field or element content.
127    fn flush_deferred_open_tag(&mut self) {
128        if let Some((element_name, element_ns, _close_name)) = self.deferred_open_tag.take() {
129            self.out.push(b'<');
130
131            // Handle namespace for element
132            if let Some(ns_uri) = element_ns {
133                if self.current_default_ns.as_deref() == Some(&ns_uri) {
134                    // Element is in the default namespace - use unprefixed form
135                    self.out.extend_from_slice(element_name.as_bytes());
136                } else {
137                    // Get or create a prefix for this namespace
138                    let prefix = self.get_or_create_prefix(&ns_uri);
139                    self.out.extend_from_slice(prefix.as_bytes());
140                    self.out.push(b':');
141                    self.out.extend_from_slice(element_name.as_bytes());
142                    // Write xmlns declaration
143                    self.out.extend_from_slice(b" xmlns:");
144                    self.out.extend_from_slice(prefix.as_bytes());
145                    self.out.extend_from_slice(b"=\"");
146                    self.out.extend_from_slice(ns_uri.as_bytes());
147                    self.out.push(b'"');
148                }
149            } else {
150                self.out.extend_from_slice(element_name.as_bytes());
151            }
152
153            // Write buffered attributes
154            let attrs: Vec<_> = self.pending_attributes.drain(..).collect();
155            let mut attrs_with_prefixes = Vec::new();
156            for (name, value, ns) in attrs {
157                let prefix = ns.as_ref().map(|uri| self.get_or_create_prefix(uri));
158                attrs_with_prefixes.push((name, value, ns, prefix));
159            }
160
161            for (attr_name, attr_value, attr_ns, prefix_opt) in attrs_with_prefixes {
162                self.out.push(b' ');
163                if let (Some(ns_uri), Some(prefix)) = (attr_ns, prefix_opt) {
164                    // Namespaced attribute - write xmlns declaration first
165                    self.out.extend_from_slice(b"xmlns:");
166                    self.out.extend_from_slice(prefix.as_bytes());
167                    self.out.extend_from_slice(b"=\"");
168                    self.out.extend_from_slice(ns_uri.as_bytes());
169                    self.out.extend_from_slice(b"\" ");
170                    // Now write the prefixed attribute
171                    self.out.extend_from_slice(prefix.as_bytes());
172                    self.out.push(b':');
173                }
174                self.out.extend_from_slice(attr_name.as_bytes());
175                self.out.extend_from_slice(b"=\"");
176                // Escape attribute value
177                for b in attr_value.as_bytes() {
178                    match *b {
179                        b'&' => self.out.extend_from_slice(b"&amp;"),
180                        b'<' => self.out.extend_from_slice(b"&lt;"),
181                        b'>' => self.out.extend_from_slice(b"&gt;"),
182                        b'"' => self.out.extend_from_slice(b"&quot;"),
183                        _ => self.out.push(*b),
184                    }
185                }
186                self.out.push(b'"');
187            }
188
189            self.out.push(b'>');
190        }
191    }
192
193    fn write_open_tag(&mut self, name: &str) {
194        self.out.push(b'<');
195
196        // Check if we have a pending namespace for this field
197        if let Some(ns_uri) = self.pending_namespace.take() {
198            // Check if this namespace matches the current default namespace
199            // If so, we can use an unprefixed element name (it inherits the default)
200            if self.current_default_ns.as_deref() == Some(&ns_uri) {
201                // Element is in the default namespace - use unprefixed form
202                self.out.extend_from_slice(name.as_bytes());
203            } else {
204                // Get or create a prefix for this namespace
205                let prefix = self.get_or_create_prefix(&ns_uri);
206
207                // Write prefixed element name
208                self.out.extend_from_slice(prefix.as_bytes());
209                self.out.push(b':');
210                self.out.extend_from_slice(name.as_bytes());
211
212                // Write xmlns declaration
213                self.out.extend_from_slice(b" xmlns:");
214                self.out.extend_from_slice(prefix.as_bytes());
215                self.out.extend_from_slice(b"=\"");
216                self.out.extend_from_slice(ns_uri.as_bytes());
217                self.out.push(b'"');
218            }
219        } else {
220            // No namespace - just write the element name
221            self.out.extend_from_slice(name.as_bytes());
222        }
223
224        // Write buffered attributes
225        // Drain attributes first to avoid borrow checker issues
226        let attrs: Vec<_> = self.pending_attributes.drain(..).collect();
227
228        // Now resolve prefixes for namespaced attributes
229        let mut attrs_with_prefixes = Vec::new();
230        for (name, value, ns) in attrs {
231            let prefix = ns.as_ref().map(|uri| self.get_or_create_prefix(uri));
232            attrs_with_prefixes.push((name, value, ns, prefix));
233        }
234
235        for (attr_name, attr_value, attr_ns, prefix_opt) in attrs_with_prefixes {
236            self.out.push(b' ');
237
238            if let (Some(ns_uri), Some(prefix)) = (attr_ns, prefix_opt) {
239                // Namespaced attribute - write xmlns declaration first
240                self.out.extend_from_slice(b"xmlns:");
241                self.out.extend_from_slice(prefix.as_bytes());
242                self.out.extend_from_slice(b"=\"");
243                self.out.extend_from_slice(ns_uri.as_bytes());
244                self.out.extend_from_slice(b"\" ");
245
246                // Now write the prefixed attribute
247                self.out.extend_from_slice(prefix.as_bytes());
248                self.out.push(b':');
249            }
250
251            self.out.extend_from_slice(attr_name.as_bytes());
252            self.out.extend_from_slice(b"=\"");
253            // Escape attribute value
254            for b in attr_value.as_bytes() {
255                match *b {
256                    b'&' => self.out.extend_from_slice(b"&amp;"),
257                    b'<' => self.out.extend_from_slice(b"&lt;"),
258                    b'>' => self.out.extend_from_slice(b"&gt;"),
259                    b'"' => self.out.extend_from_slice(b"&quot;"),
260                    _ => self.out.push(*b),
261                }
262            }
263            self.out.push(b'"');
264        }
265
266        self.out.push(b'>');
267    }
268
269    fn write_close_tag(&mut self, name: &str) {
270        self.out.extend_from_slice(b"</");
271        self.out.extend_from_slice(name.as_bytes());
272        self.out.push(b'>');
273    }
274
275    fn write_text_escaped(&mut self, text: &str) {
276        for b in text.as_bytes() {
277            match *b {
278                b'&' => self.out.extend_from_slice(b"&amp;"),
279                b'<' => self.out.extend_from_slice(b"&lt;"),
280                b'>' => self.out.extend_from_slice(b"&gt;"),
281                _ => self.out.push(*b),
282            }
283        }
284    }
285
286    fn ensure_root_tag_written(&mut self) {
287        if !self.root_tag_written {
288            self.out.extend_from_slice(b"<root");
289
290            // If ns_all is set, emit a default namespace declaration (xmlns="...")
291            // and set current_default_ns so child elements can use unprefixed form
292            if let Some(ns_all) = &self.current_ns_all {
293                self.out.extend_from_slice(b" xmlns=\"");
294                self.out.extend_from_slice(ns_all.as_bytes());
295                self.out.push(b'"');
296                self.current_default_ns = Some(ns_all.clone());
297            }
298
299            // Write buffered attributes if any (for root-level attributes)
300            let attrs: Vec<_> = self.pending_attributes.drain(..).collect();
301            let mut attrs_with_prefixes = Vec::new();
302            for (name, value, ns) in attrs {
303                let prefix = ns.as_ref().map(|uri| self.get_or_create_prefix(uri));
304                attrs_with_prefixes.push((name, value, ns, prefix));
305            }
306
307            for (attr_name, attr_value, attr_ns, prefix_opt) in attrs_with_prefixes {
308                self.out.push(b' ');
309
310                if let (Some(ns_uri), Some(prefix)) = (attr_ns, prefix_opt) {
311                    // Namespaced attribute - write xmlns declaration first
312                    self.out.extend_from_slice(b"xmlns:");
313                    self.out.extend_from_slice(prefix.as_bytes());
314                    self.out.extend_from_slice(b"=\"");
315                    self.out.extend_from_slice(ns_uri.as_bytes());
316                    self.out.extend_from_slice(b"\" ");
317
318                    // Now write the prefixed attribute
319                    self.out.extend_from_slice(prefix.as_bytes());
320                    self.out.push(b':');
321                }
322
323                self.out.extend_from_slice(attr_name.as_bytes());
324                self.out.extend_from_slice(b"=\"");
325                // Escape attribute value
326                for b in attr_value.as_bytes() {
327                    match *b {
328                        b'&' => self.out.extend_from_slice(b"&amp;"),
329                        b'<' => self.out.extend_from_slice(b"&lt;"),
330                        b'>' => self.out.extend_from_slice(b"&gt;"),
331                        b'"' => self.out.extend_from_slice(b"&quot;"),
332                        _ => self.out.push(*b),
333                    }
334                }
335                self.out.push(b'"');
336            }
337
338            self.out.push(b'>');
339            self.root_tag_written = true;
340        }
341    }
342
343    fn open_value_element_if_needed(&mut self) -> Result<Option<String>, XmlSerializeError> {
344        // Flush any deferred tag before opening a new element
345        self.flush_deferred_open_tag();
346        self.ensure_root_tag_written();
347        match self.stack.last() {
348            Some(Ctx::Root { .. }) => Ok(None),
349            Some(Ctx::Struct { .. }) => {
350                let Some(name) = self.pending_field.take() else {
351                    return Err(XmlSerializeError {
352                        msg: "value emitted in struct without field key",
353                    });
354                };
355
356                // Compute the full tag name (with prefix if namespaced) for closing
357                // If namespace matches current default, use unprefixed
358                let full_name = if let Some(ns_uri) = self.pending_namespace.clone() {
359                    if self.current_default_ns.as_deref() == Some(&ns_uri) {
360                        // Element is in the default namespace - use unprefixed form
361                        name.clone()
362                    } else {
363                        let prefix = self.get_or_create_prefix(&ns_uri);
364                        format!("{}:{}", prefix, name)
365                    }
366                } else {
367                    name.clone()
368                };
369
370                self.write_open_tag(&name);
371                Ok(Some(full_name))
372            }
373            Some(Ctx::Seq { .. }) => {
374                let name = self.item_tag.to_string();
375                self.write_open_tag(&name);
376                Ok(Some(name))
377            }
378            None => Err(XmlSerializeError {
379                msg: "serializer state missing root context",
380            }),
381        }
382    }
383
384    /// Like `open_value_element_if_needed`, but defers writing the opening tag
385    /// until we've collected all attributes. Returns the close tag name.
386    fn defer_value_element_if_needed(&mut self) -> Result<Option<String>, XmlSerializeError> {
387        self.ensure_root_tag_written();
388        match self.stack.last() {
389            Some(Ctx::Root { .. }) => Ok(None),
390            Some(Ctx::Struct { .. }) => {
391                let Some(name) = self.pending_field.take() else {
392                    return Err(XmlSerializeError {
393                        msg: "value emitted in struct without field key",
394                    });
395                };
396
397                // Compute the full tag name (with prefix if namespaced) for closing
398                let (close_name, element_ns) = if let Some(ns_uri) = self.pending_namespace.clone()
399                {
400                    if self.current_default_ns.as_deref() == Some(&ns_uri) {
401                        (name.clone(), Some(ns_uri))
402                    } else {
403                        let prefix = self.get_or_create_prefix(&ns_uri);
404                        (format!("{}:{}", prefix, name), Some(ns_uri))
405                    }
406                } else {
407                    (name.clone(), None)
408                };
409
410                // Store the deferred tag info instead of writing it
411                self.deferred_open_tag = Some((name, element_ns, close_name.clone()));
412                self.pending_namespace = None;
413                Ok(Some(close_name))
414            }
415            Some(Ctx::Seq { .. }) => {
416                // For sequences, don't defer - write immediately
417                let name = self.item_tag.to_string();
418                self.write_open_tag(&name);
419                Ok(Some(name))
420            }
421            None => Err(XmlSerializeError {
422                msg: "serializer state missing root context",
423            }),
424        }
425    }
426
427    fn enter_struct_root(&mut self) {
428        if let Some(Ctx::Root { kind }) = self.stack.last_mut() {
429            *kind = Some(Kind::Struct);
430        }
431        self.stack.push(Ctx::Struct { close: None });
432    }
433
434    fn enter_seq_root(&mut self) {
435        if let Some(Ctx::Root { kind }) = self.stack.last_mut() {
436            *kind = Some(Kind::Seq);
437        }
438        self.stack.push(Ctx::Seq { close: None });
439    }
440
441    /// Get or create a prefix for the given namespace URI.
442    /// Returns the prefix (without colon).
443    fn get_or_create_prefix(&mut self, namespace_uri: &str) -> String {
444        // Check if we've already assigned a prefix to this URI
445        if let Some(prefix) = self.declared_namespaces.get(namespace_uri) {
446            return prefix.clone();
447        }
448
449        // Try well-known namespaces
450        let prefix = WELL_KNOWN_NAMESPACES
451            .iter()
452            .find(|(uri, _)| *uri == namespace_uri)
453            .map(|(_, prefix)| (*prefix).to_string())
454            .unwrap_or_else(|| {
455                // Auto-generate a prefix
456                let prefix = format!("ns{}", self.next_ns_index);
457                self.next_ns_index += 1;
458                prefix
459            });
460
461        // Ensure the prefix isn't already in use for a different namespace
462        let final_prefix = if self.declared_namespaces.values().any(|p| p == &prefix) {
463            // Conflict! Generate a new one
464            let prefix = format!("ns{}", self.next_ns_index);
465            self.next_ns_index += 1;
466            prefix
467        } else {
468            prefix
469        };
470
471        self.declared_namespaces
472            .insert(namespace_uri.to_string(), final_prefix.clone());
473        final_prefix
474    }
475}
476
477impl Default for XmlSerializer {
478    fn default() -> Self {
479        Self::new()
480    }
481}
482
483impl FormatSerializer for XmlSerializer {
484    type Error = XmlSerializeError;
485
486    fn begin_struct(&mut self) -> Result<(), Self::Error> {
487        // Flush any deferred tag from parent before starting a new struct
488        self.flush_deferred_open_tag();
489
490        match self.stack.last() {
491            Some(Ctx::Root { kind: None }) => {
492                self.enter_struct_root();
493                Ok(())
494            }
495            Some(Ctx::Root {
496                kind: Some(Kind::Struct),
497            }) => Err(XmlSerializeError {
498                msg: "multiple root values are not supported",
499            }),
500            Some(Ctx::Root {
501                kind: Some(Kind::Seq),
502            })
503            | Some(Ctx::Seq { .. })
504            | Some(Ctx::Struct { .. }) => {
505                // For nested structs, defer the opening tag until we've collected all attributes
506                let close = self.defer_value_element_if_needed()?;
507                self.stack.push(Ctx::Struct { close });
508                Ok(())
509            }
510            None => Err(XmlSerializeError {
511                msg: "serializer state missing root context",
512            }),
513        }
514    }
515
516    fn field_key(&mut self, key: &str) -> Result<(), Self::Error> {
517        self.pending_field = Some(key.to_string());
518        Ok(())
519    }
520
521    fn end_struct(&mut self) -> Result<(), Self::Error> {
522        // Flush any deferred opening tag before closing
523        self.flush_deferred_open_tag();
524
525        match self.stack.pop() {
526            Some(Ctx::Struct { close }) => {
527                if let Some(name) = close {
528                    self.write_close_tag(&name);
529                }
530                Ok(())
531            }
532            _ => Err(XmlSerializeError {
533                msg: "end_struct called without matching begin_struct",
534            }),
535        }
536    }
537
538    fn begin_seq(&mut self) -> Result<(), Self::Error> {
539        match self.stack.last() {
540            Some(Ctx::Root { kind: None }) => {
541                self.enter_seq_root();
542                Ok(())
543            }
544            Some(Ctx::Root {
545                kind: Some(Kind::Seq),
546            }) => Err(XmlSerializeError {
547                msg: "multiple root values are not supported",
548            }),
549            Some(Ctx::Root {
550                kind: Some(Kind::Struct),
551            })
552            | Some(Ctx::Seq { .. })
553            | Some(Ctx::Struct { .. }) => {
554                let close = self.open_value_element_if_needed()?;
555                self.stack.push(Ctx::Seq { close });
556                Ok(())
557            }
558            None => Err(XmlSerializeError {
559                msg: "serializer state missing root context",
560            }),
561        }
562    }
563
564    fn end_seq(&mut self) -> Result<(), Self::Error> {
565        match self.stack.pop() {
566            Some(Ctx::Seq { close }) => {
567                if let Some(name) = close {
568                    self.write_close_tag(&name);
569                }
570                Ok(())
571            }
572            _ => Err(XmlSerializeError {
573                msg: "end_seq called without matching begin_seq",
574            }),
575        }
576    }
577
578    fn scalar(&mut self, scalar: ScalarValue<'_>) -> Result<(), Self::Error> {
579        // If this is an attribute, buffer it instead of writing as a child element
580        if self.pending_is_attribute {
581            let name = self.pending_field.take().ok_or(XmlSerializeError {
582                msg: "attribute value without field name",
583            })?;
584            let namespace = self.pending_namespace.take();
585
586            // Convert scalar to string for attribute value
587            let value = match scalar {
588                ScalarValue::Null => "null".to_string(),
589                ScalarValue::Bool(v) => if v { "true" } else { "false" }.to_string(),
590                ScalarValue::I64(v) => v.to_string(),
591                ScalarValue::U64(v) => v.to_string(),
592                ScalarValue::I128(v) => v.to_string(),
593                ScalarValue::U128(v) => v.to_string(),
594                ScalarValue::F64(v) => v.to_string(),
595                ScalarValue::Str(s) => s.into_owned(),
596                ScalarValue::Bytes(_) => {
597                    return Err(XmlSerializeError {
598                        msg: "bytes serialization unsupported for xml",
599                    });
600                }
601            };
602
603            self.pending_attributes.push((name, value, namespace));
604            self.pending_is_attribute = false;
605            return Ok(());
606        }
607
608        // If this is text content (xml::text), write it directly without element wrapper
609        if self.pending_is_text {
610            // Clear pending field - we're writing text content, not an element
611            self.pending_field = None;
612            self.pending_namespace = None;
613            self.pending_is_text = false;
614
615            // Flush any deferred opening tag first
616            self.flush_deferred_open_tag();
617            self.ensure_root_tag_written();
618
619            // Write the text content directly
620            match scalar {
621                ScalarValue::Null => self.write_text_escaped("null"),
622                ScalarValue::Bool(v) => self.write_text_escaped(if v { "true" } else { "false" }),
623                ScalarValue::I64(v) => self.write_text_escaped(&v.to_string()),
624                ScalarValue::U64(v) => self.write_text_escaped(&v.to_string()),
625                ScalarValue::I128(v) => self.write_text_escaped(&v.to_string()),
626                ScalarValue::U128(v) => self.write_text_escaped(&v.to_string()),
627                ScalarValue::F64(v) => self.write_text_escaped(&v.to_string()),
628                ScalarValue::Str(s) => self.write_text_escaped(&s),
629                ScalarValue::Bytes(_) => {
630                    return Err(XmlSerializeError {
631                        msg: "bytes serialization unsupported for xml",
632                    });
633                }
634            }
635            return Ok(());
636        }
637
638        // Regular child element
639        let close = self.open_value_element_if_needed()?;
640
641        match scalar {
642            ScalarValue::Null => {
643                // Encode as the literal "null" to round-trip through parse_scalar.
644                self.write_text_escaped("null");
645            }
646            ScalarValue::Bool(v) => self.write_text_escaped(if v { "true" } else { "false" }),
647            ScalarValue::I64(v) => self.write_text_escaped(&v.to_string()),
648            ScalarValue::U64(v) => self.write_text_escaped(&v.to_string()),
649            ScalarValue::I128(v) => self.write_text_escaped(&v.to_string()),
650            ScalarValue::U128(v) => self.write_text_escaped(&v.to_string()),
651            ScalarValue::F64(v) => self.write_text_escaped(&v.to_string()),
652            ScalarValue::Str(s) => self.write_text_escaped(&s),
653            ScalarValue::Bytes(_) => {
654                return Err(XmlSerializeError {
655                    msg: "bytes serialization unsupported for xml",
656                });
657            }
658        }
659
660        if let Some(name) = close {
661            self.write_close_tag(&name);
662        }
663
664        Ok(())
665    }
666
667    fn field_metadata(&mut self, field: &facet_reflect::FieldItem) -> Result<(), Self::Error> {
668        // Check if this field is an attribute
669        self.pending_is_attribute = field.field.get_attr(Some("xml"), "attribute").is_some();
670        // Check if this field is text content
671        self.pending_is_text = field.field.get_attr(Some("xml"), "text").is_some();
672
673        // Extract xml::ns attribute from the field
674        if let Some(ns_attr) = field.field.get_attr(Some("xml"), "ns")
675            && let Some(ns_uri) = ns_attr.get_as::<&str>().copied()
676        {
677            self.pending_namespace = Some(ns_uri.to_string());
678            return Ok(());
679        }
680
681        // If field doesn't have explicit xml::ns, check for container-level xml::ns_all
682        // Only apply ns_all to elements, not attributes or text content (per XML spec)
683        if !self.pending_is_attribute
684            && !self.pending_is_text
685            && let Some(ns_all) = &self.current_ns_all
686        {
687            self.pending_namespace = Some(ns_all.clone());
688        }
689
690        Ok(())
691    }
692
693    fn struct_metadata(&mut self, shape: &facet_core::Shape) -> Result<(), Self::Error> {
694        // Extract xml::ns_all attribute from the struct
695        self.current_ns_all = shape
696            .attributes
697            .iter()
698            .find(|attr| attr.ns == Some("xml") && attr.key == "ns_all")
699            .and_then(|attr| attr.get_as::<&str>().copied())
700            .map(String::from);
701        Ok(())
702    }
703
704    /// For XML, `None` values should not emit any content.
705    /// We skip emitting an element entirely rather than writing `<field>null</field>`.
706    fn serialize_none(&mut self) -> Result<(), Self::Error> {
707        // Clear pending field state - we're skipping this value
708        self.pending_field = None;
709        self.pending_namespace = None;
710        self.pending_is_attribute = false;
711        self.pending_is_text = false;
712        // Do nothing - don't emit anything for None
713        Ok(())
714    }
715
716    fn preferred_field_order(&self) -> facet_format::FieldOrdering {
717        facet_format::FieldOrdering::AttributesFirst
718    }
719}
720
721pub fn to_vec<'facet, T>(value: &'_ T) -> Result<Vec<u8>, SerializeError<XmlSerializeError>>
722where
723    T: Facet<'facet> + ?Sized,
724{
725    let mut serializer = XmlSerializer::new();
726    serialize_root(&mut serializer, Peek::new(value))?;
727    Ok(serializer.finish())
728}