1extern crate alloc;
2
3use alloc::{borrow::Cow, format, string::String, vec::Vec};
4use std::{collections::HashMap, io::Write};
5
6use facet_core::Facet;
7use facet_format::{FormatSerializer, ScalarValue, SerializeError, serialize_root};
8use facet_reflect::Peek;
9
10pub type FloatFormatter = fn(f64, &mut dyn Write) -> std::io::Result<()>;
16
17#[derive(Clone)]
19pub struct SerializeOptions {
20 pub pretty: bool,
22 pub indent: Cow<'static, str>,
24 pub float_formatter: Option<FloatFormatter>,
27 pub preserve_entities: bool,
35}
36
37impl Default for SerializeOptions {
38 fn default() -> Self {
39 Self {
40 pretty: false,
41 indent: Cow::Borrowed(" "),
42 float_formatter: None,
43 preserve_entities: false,
44 }
45 }
46}
47
48impl core::fmt::Debug for SerializeOptions {
49 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
50 f.debug_struct("SerializeOptions")
51 .field("pretty", &self.pretty)
52 .field("indent", &self.indent)
53 .field("float_formatter", &self.float_formatter.map(|_| "..."))
54 .field("preserve_entities", &self.preserve_entities)
55 .finish()
56 }
57}
58
59impl SerializeOptions {
60 pub fn new() -> Self {
62 Self::default()
63 }
64
65 pub fn pretty(mut self) -> Self {
67 self.pretty = true;
68 self
69 }
70
71 pub fn indent(mut self, indent: impl Into<Cow<'static, str>>) -> Self {
73 self.indent = indent.into();
74 self.pretty = true;
75 self
76 }
77
78 pub fn float_formatter(mut self, formatter: FloatFormatter) -> Self {
111 self.float_formatter = Some(formatter);
112 self
113 }
114
115 pub fn preserve_entities(mut self, preserve: bool) -> Self {
123 self.preserve_entities = preserve;
124 self
125 }
126}
127
128#[allow(dead_code)] const WELL_KNOWN_NAMESPACES: &[(&str, &str)] = &[
131 ("http://www.w3.org/2001/XMLSchema-instance", "xsi"),
132 ("http://www.w3.org/2001/XMLSchema", "xs"),
133 ("http://www.w3.org/XML/1998/namespace", "xml"),
134 ("http://www.w3.org/1999/xlink", "xlink"),
135 ("http://www.w3.org/2000/svg", "svg"),
136 ("http://www.w3.org/1999/xhtml", "xhtml"),
137 ("http://schemas.xmlsoap.org/soap/envelope/", "soap"),
138 ("http://www.w3.org/2003/05/soap-envelope", "soap12"),
139 ("http://schemas.android.com/apk/res/android", "android"),
140];
141
142#[derive(Debug)]
143pub struct XmlSerializeError {
144 msg: &'static str,
145}
146
147impl core::fmt::Display for XmlSerializeError {
148 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
149 f.write_str(self.msg)
150 }
151}
152
153impl std::error::Error for XmlSerializeError {}
154
155#[derive(Debug)]
156enum Ctx {
157 Root { kind: Option<Kind> },
158 Struct { close: Option<String> },
159 Seq { close: Option<String> },
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163enum Kind {
164 Struct,
165 Seq,
166}
167
168pub struct XmlSerializer {
175 out: Vec<u8>,
176 stack: Vec<Ctx>,
177 pending_field: Option<String>,
178 pending_namespace: Option<String>,
180 pending_is_attribute: bool,
182 pending_is_text: bool,
184 pending_is_elements: bool,
186 current_ns_all: Option<String>,
188 pending_attributes: Vec<(String, String, Option<String>)>,
190 item_tag: &'static str,
191 declared_namespaces: HashMap<String, String>,
193 next_ns_index: usize,
195 current_default_ns: Option<String>,
198 root_tag_written: bool,
200 root_element_name: Option<String>,
202 deferred_open_tag: Option<(String, Option<String>, String)>,
206 elements_stack: Vec<bool>,
209 skip_enum_wrapper: Option<String>,
214 options: SerializeOptions,
216 depth: usize,
218}
219
220impl XmlSerializer {
221 pub fn new() -> Self {
223 Self::with_options(SerializeOptions::default())
224 }
225
226 pub fn with_options(options: SerializeOptions) -> Self {
228 Self {
229 out: Vec::new(),
230 stack: vec![Ctx::Root { kind: None }],
231 pending_field: None,
232 pending_namespace: None,
233 pending_is_attribute: false,
234 pending_is_text: false,
235 pending_is_elements: false,
236 current_ns_all: None,
237 pending_attributes: Vec::new(),
238 item_tag: "item",
239 declared_namespaces: HashMap::new(),
240 next_ns_index: 0,
241 current_default_ns: None,
242 root_tag_written: false,
243 root_element_name: None,
244 deferred_open_tag: None,
245 elements_stack: Vec::new(),
246 skip_enum_wrapper: None,
247 options,
248 depth: 0,
249 }
250 }
251
252 pub fn finish(mut self) -> Vec<u8> {
253 self.ensure_root_tag_written();
255
256 while let Some(ctx) = self.stack.pop() {
258 match ctx {
259 Ctx::Root { .. } => break,
260 Ctx::Struct { close } | Ctx::Seq { close } => {
261 if let Some(name) = close {
262 self.write_close_tag(&name, true);
263 }
264 }
265 }
266 }
267 self.depth = self.depth.saturating_sub(1);
269 self.write_indent();
270 let root_name = self.root_element_name.as_deref().unwrap_or("root");
271 self.out.extend_from_slice(b"</");
272 self.out.extend_from_slice(root_name.as_bytes());
273 self.out.push(b'>');
274 self.out
275 }
276
277 fn flush_deferred_open_tag(&mut self) {
280 if let Some((element_name, element_ns, _close_name)) = self.deferred_open_tag.take() {
281 self.write_indent();
282 self.out.push(b'<');
283
284 if let Some(ns_uri) = element_ns {
286 if self.current_default_ns.as_deref() == Some(&ns_uri) {
287 self.out.extend_from_slice(element_name.as_bytes());
289 } else {
290 let prefix = self.get_or_create_prefix(&ns_uri);
292 self.out.extend_from_slice(prefix.as_bytes());
293 self.out.push(b':');
294 self.out.extend_from_slice(element_name.as_bytes());
295 self.out.extend_from_slice(b" xmlns:");
297 self.out.extend_from_slice(prefix.as_bytes());
298 self.out.extend_from_slice(b"=\"");
299 self.out.extend_from_slice(ns_uri.as_bytes());
300 self.out.push(b'"');
301 }
302 } else {
303 self.out.extend_from_slice(element_name.as_bytes());
304 }
305
306 let attrs: Vec<_> = self.pending_attributes.drain(..).collect();
308 let mut attrs_with_prefixes = Vec::new();
309 for (name, value, ns) in attrs {
310 let prefix = ns.as_ref().map(|uri| self.get_or_create_prefix(uri));
311 attrs_with_prefixes.push((name, value, ns, prefix));
312 }
313
314 for (attr_name, attr_value, attr_ns, prefix_opt) in attrs_with_prefixes {
315 self.out.push(b' ');
316 if let (Some(ns_uri), Some(prefix)) = (attr_ns, prefix_opt) {
317 self.out.extend_from_slice(b"xmlns:");
319 self.out.extend_from_slice(prefix.as_bytes());
320 self.out.extend_from_slice(b"=\"");
321 self.out.extend_from_slice(ns_uri.as_bytes());
322 self.out.extend_from_slice(b"\" ");
323 self.out.extend_from_slice(prefix.as_bytes());
325 self.out.push(b':');
326 }
327 self.out.extend_from_slice(attr_name.as_bytes());
328 self.out.extend_from_slice(b"=\"");
329 for b in attr_value.as_bytes() {
331 match *b {
332 b'&' => self.out.extend_from_slice(b"&"),
333 b'<' => self.out.extend_from_slice(b"<"),
334 b'>' => self.out.extend_from_slice(b">"),
335 b'"' => self.out.extend_from_slice(b"""),
336 _ => self.out.push(*b),
337 }
338 }
339 self.out.push(b'"');
340 }
341
342 self.out.push(b'>');
343 self.write_newline();
344 self.depth += 1;
345 }
346 }
347
348 fn write_open_tag(&mut self, name: &str) {
349 self.write_indent();
350 self.out.push(b'<');
351
352 if let Some(ns_uri) = self.pending_namespace.take() {
354 if self.current_default_ns.as_deref() == Some(&ns_uri) {
357 self.out.extend_from_slice(name.as_bytes());
359 } else {
360 let prefix = self.get_or_create_prefix(&ns_uri);
362
363 self.out.extend_from_slice(prefix.as_bytes());
365 self.out.push(b':');
366 self.out.extend_from_slice(name.as_bytes());
367
368 self.out.extend_from_slice(b" xmlns:");
370 self.out.extend_from_slice(prefix.as_bytes());
371 self.out.extend_from_slice(b"=\"");
372 self.out.extend_from_slice(ns_uri.as_bytes());
373 self.out.push(b'"');
374 }
375 } else {
376 self.out.extend_from_slice(name.as_bytes());
378 }
379
380 let attrs: Vec<_> = self.pending_attributes.drain(..).collect();
383
384 let mut attrs_with_prefixes = Vec::new();
386 for (name, value, ns) in attrs {
387 let prefix = ns.as_ref().map(|uri| self.get_or_create_prefix(uri));
388 attrs_with_prefixes.push((name, value, ns, prefix));
389 }
390
391 for (attr_name, attr_value, attr_ns, prefix_opt) in attrs_with_prefixes {
392 self.out.push(b' ');
393
394 if let (Some(ns_uri), Some(prefix)) = (attr_ns, prefix_opt) {
395 self.out.extend_from_slice(b"xmlns:");
397 self.out.extend_from_slice(prefix.as_bytes());
398 self.out.extend_from_slice(b"=\"");
399 self.out.extend_from_slice(ns_uri.as_bytes());
400 self.out.extend_from_slice(b"\" ");
401
402 self.out.extend_from_slice(prefix.as_bytes());
404 self.out.push(b':');
405 }
406
407 self.out.extend_from_slice(attr_name.as_bytes());
408 self.out.extend_from_slice(b"=\"");
409 for b in attr_value.as_bytes() {
411 match *b {
412 b'&' => self.out.extend_from_slice(b"&"),
413 b'<' => self.out.extend_from_slice(b"<"),
414 b'>' => self.out.extend_from_slice(b">"),
415 b'"' => self.out.extend_from_slice(b"""),
416 _ => self.out.push(*b),
417 }
418 }
419 self.out.push(b'"');
420 }
421
422 self.out.push(b'>');
423 }
424
425 fn write_close_tag(&mut self, name: &str, block: bool) {
429 if block {
430 self.depth = self.depth.saturating_sub(1);
431 self.write_indent();
432 }
433 self.out.extend_from_slice(b"</");
434 self.out.extend_from_slice(name.as_bytes());
435 self.out.push(b'>');
436 if block {
437 self.write_newline();
438 }
439 }
440
441 fn write_text_escaped(&mut self, text: &str) {
442 if self.options.preserve_entities {
443 let escaped = escape_preserving_entities(text, false);
444 self.out.extend_from_slice(escaped.as_bytes());
445 } else {
446 for b in text.as_bytes() {
447 match *b {
448 b'&' => self.out.extend_from_slice(b"&"),
449 b'<' => self.out.extend_from_slice(b"<"),
450 b'>' => self.out.extend_from_slice(b">"),
451 _ => self.out.push(*b),
452 }
453 }
454 }
455 }
456
457 fn format_float(&self, v: f64) -> String {
459 if let Some(fmt) = self.options.float_formatter {
460 let mut buf = Vec::new();
461 if fmt(v, &mut buf).is_ok()
462 && let Ok(s) = String::from_utf8(buf)
463 {
464 return s;
465 }
466 }
467 #[cfg(feature = "fast")]
468 return zmij::Buffer::new().format(v).to_string();
469 #[cfg(not(feature = "fast"))]
470 v.to_string()
471 }
472
473 fn write_indent(&mut self) {
475 if self.options.pretty {
476 for _ in 0..self.depth {
477 self.out.extend_from_slice(self.options.indent.as_bytes());
478 }
479 }
480 }
481
482 fn write_newline(&mut self) {
484 if self.options.pretty {
485 self.out.push(b'\n');
486 }
487 }
488
489 fn ensure_root_tag_written(&mut self) {
490 if !self.root_tag_written {
491 let root_name = self.root_element_name.as_deref().unwrap_or("root");
492 self.out.push(b'<');
493 self.out.extend_from_slice(root_name.as_bytes());
494
495 if let Some(ns_all) = &self.current_ns_all {
498 self.out.extend_from_slice(b" xmlns=\"");
499 self.out.extend_from_slice(ns_all.as_bytes());
500 self.out.push(b'"');
501 self.current_default_ns = Some(ns_all.clone());
502 }
503
504 let attrs: Vec<_> = self.pending_attributes.drain(..).collect();
506 let mut attrs_with_prefixes = Vec::new();
507 for (name, value, ns) in attrs {
508 let prefix = ns.as_ref().map(|uri| self.get_or_create_prefix(uri));
509 attrs_with_prefixes.push((name, value, ns, prefix));
510 }
511
512 for (attr_name, attr_value, attr_ns, prefix_opt) in attrs_with_prefixes {
513 self.out.push(b' ');
514
515 if let (Some(ns_uri), Some(prefix)) = (attr_ns, prefix_opt) {
516 self.out.extend_from_slice(b"xmlns:");
518 self.out.extend_from_slice(prefix.as_bytes());
519 self.out.extend_from_slice(b"=\"");
520 self.out.extend_from_slice(ns_uri.as_bytes());
521 self.out.extend_from_slice(b"\" ");
522
523 self.out.extend_from_slice(prefix.as_bytes());
525 self.out.push(b':');
526 }
527
528 self.out.extend_from_slice(attr_name.as_bytes());
529 self.out.extend_from_slice(b"=\"");
530 for b in attr_value.as_bytes() {
532 match *b {
533 b'&' => self.out.extend_from_slice(b"&"),
534 b'<' => self.out.extend_from_slice(b"<"),
535 b'>' => self.out.extend_from_slice(b">"),
536 b'"' => self.out.extend_from_slice(b"""),
537 _ => self.out.push(*b),
538 }
539 }
540 self.out.push(b'"');
541 }
542
543 self.out.push(b'>');
544 self.write_newline();
545 self.depth += 1;
546 self.root_tag_written = true;
547 }
548 }
549
550 fn open_value_element_if_needed(&mut self) -> Result<Option<String>, XmlSerializeError> {
551 self.flush_deferred_open_tag();
553 self.ensure_root_tag_written();
554 match self.stack.last() {
555 Some(Ctx::Root { .. }) => Ok(None),
556 Some(Ctx::Struct { .. }) => {
557 let Some(name) = self.pending_field.take() else {
558 return Err(XmlSerializeError {
559 msg: "value emitted in struct without field key",
560 });
561 };
562
563 let full_name = if let Some(ns_uri) = self.pending_namespace.clone() {
566 if self.current_default_ns.as_deref() == Some(&ns_uri) {
567 name.clone()
569 } else {
570 let prefix = self.get_or_create_prefix(&ns_uri);
571 format!("{}:{}", prefix, name)
572 }
573 } else {
574 name.clone()
575 };
576
577 self.write_open_tag(&name);
578 Ok(Some(full_name))
579 }
580 Some(Ctx::Seq { .. }) => {
581 let name = self.item_tag.to_string();
582 self.write_open_tag(&name);
583 Ok(Some(name))
584 }
585 None => Err(XmlSerializeError {
586 msg: "serializer state missing root context",
587 }),
588 }
589 }
590
591 fn defer_value_element_if_needed(&mut self) -> Result<Option<String>, XmlSerializeError> {
594 self.ensure_root_tag_written();
595 match self.stack.last() {
596 Some(Ctx::Root { .. }) => Ok(None),
597 Some(Ctx::Struct { .. }) => {
598 let Some(name) = self.pending_field.take() else {
599 return Err(XmlSerializeError {
600 msg: "value emitted in struct without field key",
601 });
602 };
603
604 let (close_name, element_ns) = if let Some(ns_uri) = self.pending_namespace.clone()
606 {
607 if self.current_default_ns.as_deref() == Some(&ns_uri) {
608 (name.clone(), Some(ns_uri))
609 } else {
610 let prefix = self.get_or_create_prefix(&ns_uri);
611 (format!("{}:{}", prefix, name), Some(ns_uri))
612 }
613 } else {
614 (name.clone(), None)
615 };
616
617 self.deferred_open_tag = Some((name, element_ns, close_name.clone()));
619 self.pending_namespace = None;
620 Ok(Some(close_name))
621 }
622 Some(Ctx::Seq { .. }) => {
623 if let Some(name) = self.pending_field.take() {
626 let (close_name, element_ns) =
628 if let Some(ns_uri) = self.pending_namespace.clone() {
629 if self.current_default_ns.as_deref() == Some(&ns_uri) {
630 (name.clone(), Some(ns_uri))
631 } else {
632 let prefix = self.get_or_create_prefix(&ns_uri);
633 (format!("{}:{}", prefix, name), Some(ns_uri))
634 }
635 } else {
636 (name.clone(), None)
637 };
638 self.deferred_open_tag = Some((name, element_ns, close_name.clone()));
639 self.pending_namespace = None;
640 Ok(Some(close_name))
641 } else {
642 let name = self.item_tag.to_string();
644 self.write_open_tag(&name);
645 Ok(Some(name))
646 }
647 }
648 None => Err(XmlSerializeError {
649 msg: "serializer state missing root context",
650 }),
651 }
652 }
653
654 fn enter_struct_root(&mut self) {
655 if let Some(Ctx::Root { kind }) = self.stack.last_mut() {
656 *kind = Some(Kind::Struct);
657 }
658 self.stack.push(Ctx::Struct { close: None });
659 }
660
661 fn enter_seq_root(&mut self) {
662 if let Some(Ctx::Root { kind }) = self.stack.last_mut() {
663 *kind = Some(Kind::Seq);
664 }
665 self.stack.push(Ctx::Seq { close: None });
666 }
667
668 fn get_or_create_prefix(&mut self, namespace_uri: &str) -> String {
671 if let Some(prefix) = self.declared_namespaces.get(namespace_uri) {
673 return prefix.clone();
674 }
675
676 let prefix = WELL_KNOWN_NAMESPACES
678 .iter()
679 .find(|(uri, _)| *uri == namespace_uri)
680 .map(|(_, prefix)| (*prefix).to_string())
681 .unwrap_or_else(|| {
682 let prefix = format!("ns{}", self.next_ns_index);
684 self.next_ns_index += 1;
685 prefix
686 });
687
688 let final_prefix = if self.declared_namespaces.values().any(|p| p == &prefix) {
690 let prefix = format!("ns{}", self.next_ns_index);
692 self.next_ns_index += 1;
693 prefix
694 } else {
695 prefix
696 };
697
698 self.declared_namespaces
699 .insert(namespace_uri.to_string(), final_prefix.clone());
700 final_prefix
701 }
702}
703
704impl Default for XmlSerializer {
705 fn default() -> Self {
706 Self::new()
707 }
708}
709
710impl FormatSerializer for XmlSerializer {
711 type Error = XmlSerializeError;
712
713 fn begin_struct(&mut self) -> Result<(), Self::Error> {
714 self.flush_deferred_open_tag();
716
717 if self.skip_enum_wrapper.is_some() {
720 self.stack.push(Ctx::Struct { close: None });
721 return Ok(());
722 }
723
724 match self.stack.last() {
725 Some(Ctx::Root { kind: None }) => {
726 self.enter_struct_root();
727 Ok(())
728 }
729 Some(Ctx::Root {
730 kind: Some(Kind::Struct),
731 }) => Err(XmlSerializeError {
732 msg: "multiple root values are not supported",
733 }),
734 Some(Ctx::Root {
735 kind: Some(Kind::Seq),
736 })
737 | Some(Ctx::Seq { .. })
738 | Some(Ctx::Struct { .. }) => {
739 let close = self.defer_value_element_if_needed()?;
741 self.stack.push(Ctx::Struct { close });
742 Ok(())
743 }
744 None => Err(XmlSerializeError {
745 msg: "serializer state missing root context",
746 }),
747 }
748 }
749
750 fn field_key(&mut self, key: &str) -> Result<(), Self::Error> {
751 if let Some(ref variant_name) = self.skip_enum_wrapper
754 && key == variant_name
755 {
756 self.skip_enum_wrapper = None;
759 return Ok(());
760 }
761 self.pending_field = Some(key.to_string());
762 Ok(())
763 }
764
765 fn end_struct(&mut self) -> Result<(), Self::Error> {
766 self.flush_deferred_open_tag();
768
769 match self.stack.pop() {
770 Some(Ctx::Struct { close }) => {
771 if let Some(name) = close {
772 self.write_close_tag(&name, true);
773 }
774 Ok(())
775 }
776 _ => Err(XmlSerializeError {
777 msg: "end_struct called without matching begin_struct",
778 }),
779 }
780 }
781
782 fn begin_seq(&mut self) -> Result<(), Self::Error> {
783 let is_elements = self.pending_is_elements;
785 self.pending_is_elements = false;
786 self.elements_stack.push(is_elements);
787
788 match self.stack.last() {
789 Some(Ctx::Root { kind: None }) => {
790 self.enter_seq_root();
791 Ok(())
792 }
793 Some(Ctx::Root {
794 kind: Some(Kind::Seq),
795 }) => Err(XmlSerializeError {
796 msg: "multiple root values are not supported",
797 }),
798 Some(Ctx::Root {
799 kind: Some(Kind::Struct),
800 })
801 | Some(Ctx::Seq { .. })
802 | Some(Ctx::Struct { .. }) => {
803 if is_elements {
805 self.pending_field = None;
806 self.pending_namespace = None;
807 self.stack.push(Ctx::Seq { close: None });
808 } else {
809 let close = self.open_value_element_if_needed()?;
810 self.stack.push(Ctx::Seq { close });
811 }
812 Ok(())
813 }
814 None => Err(XmlSerializeError {
815 msg: "serializer state missing root context",
816 }),
817 }
818 }
819
820 fn end_seq(&mut self) -> Result<(), Self::Error> {
821 self.elements_stack.pop();
823
824 match self.stack.pop() {
825 Some(Ctx::Seq { close }) => {
826 if let Some(name) = close {
827 self.write_close_tag(&name, true);
828 }
829 Ok(())
830 }
831 _ => Err(XmlSerializeError {
832 msg: "end_seq called without matching begin_seq",
833 }),
834 }
835 }
836
837 fn scalar(&mut self, scalar: ScalarValue<'_>) -> Result<(), Self::Error> {
838 if self.pending_is_attribute {
840 let name = self.pending_field.take().ok_or(XmlSerializeError {
841 msg: "attribute value without field name",
842 })?;
843 let namespace = self.pending_namespace.take();
844
845 let value = match scalar {
847 ScalarValue::Null => "null".to_string(),
848 ScalarValue::Bool(v) => if v { "true" } else { "false" }.to_string(),
849 ScalarValue::Char(c) => c.to_string(),
850 ScalarValue::I64(v) => v.to_string(),
851 ScalarValue::U64(v) => v.to_string(),
852 ScalarValue::I128(v) => v.to_string(),
853 ScalarValue::U128(v) => v.to_string(),
854 ScalarValue::F64(v) => self.format_float(v),
855 ScalarValue::Str(s) | ScalarValue::StringlyTyped(s) => s.into_owned(),
856 ScalarValue::Bytes(_) => {
857 return Err(XmlSerializeError {
858 msg: "bytes serialization unsupported for xml",
859 });
860 }
861 };
862
863 self.pending_attributes.push((name, value, namespace));
864 self.pending_is_attribute = false;
865 return Ok(());
866 }
867
868 if self.pending_is_text {
870 self.pending_field = None;
872 self.pending_namespace = None;
873 self.pending_is_text = false;
874
875 self.flush_deferred_open_tag();
877 self.ensure_root_tag_written();
878
879 match scalar {
881 ScalarValue::Null => self.write_text_escaped("null"),
882 ScalarValue::Bool(v) => self.write_text_escaped(if v { "true" } else { "false" }),
883 ScalarValue::Char(c) => {
884 let mut buf = [0u8; 4];
885 self.write_text_escaped(c.encode_utf8(&mut buf));
886 }
887 ScalarValue::I64(v) => self.write_text_escaped(&v.to_string()),
888 ScalarValue::U64(v) => self.write_text_escaped(&v.to_string()),
889 ScalarValue::I128(v) => self.write_text_escaped(&v.to_string()),
890 ScalarValue::U128(v) => self.write_text_escaped(&v.to_string()),
891 ScalarValue::F64(v) => {
892 let formatted = self.format_float(v);
893 self.write_text_escaped(&formatted);
894 }
895 ScalarValue::Str(s) | ScalarValue::StringlyTyped(s) => self.write_text_escaped(&s),
896 ScalarValue::Bytes(_) => {
897 return Err(XmlSerializeError {
898 msg: "bytes serialization unsupported for xml",
899 });
900 }
901 }
902 return Ok(());
903 }
904
905 let close = self.open_value_element_if_needed()?;
907
908 match scalar {
909 ScalarValue::Null => {
910 self.write_text_escaped("null");
912 }
913 ScalarValue::Bool(v) => self.write_text_escaped(if v { "true" } else { "false" }),
914 ScalarValue::Char(c) => {
915 let mut buf = [0u8; 4];
916 self.write_text_escaped(c.encode_utf8(&mut buf));
917 }
918 ScalarValue::I64(v) => self.write_text_escaped(&v.to_string()),
919 ScalarValue::U64(v) => self.write_text_escaped(&v.to_string()),
920 ScalarValue::I128(v) => self.write_text_escaped(&v.to_string()),
921 ScalarValue::U128(v) => self.write_text_escaped(&v.to_string()),
922 ScalarValue::F64(v) => {
923 let formatted = self.format_float(v);
924 self.write_text_escaped(&formatted);
925 }
926 ScalarValue::Str(s) | ScalarValue::StringlyTyped(s) => self.write_text_escaped(&s),
927 ScalarValue::Bytes(_) => {
928 return Err(XmlSerializeError {
929 msg: "bytes serialization unsupported for xml",
930 });
931 }
932 }
933
934 if let Some(name) = close {
935 self.write_close_tag(&name, false);
937 self.write_newline();
938 }
939
940 Ok(())
941 }
942
943 fn field_metadata(&mut self, field: &facet_reflect::FieldItem) -> Result<(), Self::Error> {
944 let Some(field_def) = field.field else {
946 self.pending_is_attribute = true;
947 self.pending_is_text = false;
948 self.pending_is_elements = false;
949 return Ok(());
950 };
951
952 self.pending_is_attribute = field_def.get_attr(Some("xml"), "attribute").is_some();
954 self.pending_is_text = field_def.get_attr(Some("xml"), "text").is_some();
956 self.pending_is_elements = field_def.get_attr(Some("xml"), "elements").is_some();
958
959 if let Some(ns_attr) = field_def.get_attr(Some("xml"), "ns")
961 && let Some(ns_uri) = ns_attr.get_as::<&str>().copied()
962 {
963 self.pending_namespace = Some(ns_uri.to_string());
964 return Ok(());
965 }
966
967 if !self.pending_is_attribute
970 && !self.pending_is_text
971 && let Some(ns_all) = &self.current_ns_all
972 {
973 self.pending_namespace = Some(ns_all.clone());
974 }
975
976 Ok(())
977 }
978
979 fn struct_metadata(&mut self, shape: &facet_core::Shape) -> Result<(), Self::Error> {
980 self.current_ns_all = shape
982 .attributes
983 .iter()
984 .find(|attr| attr.ns == Some("xml") && attr.key == "ns_all")
985 .and_then(|attr| attr.get_as::<&str>().copied())
986 .map(String::from);
987
988 let element_name = shape
990 .get_builtin_attr_value::<&str>("rename")
991 .unwrap_or(shape.type_identifier);
992
993 if matches!(self.stack.last(), Some(Ctx::Root { kind: None })) {
995 self.root_element_name = Some(element_name.to_string());
996 }
997
998 if self.elements_stack.last() == Some(&true) && self.pending_field.is_none() {
1000 self.pending_field = Some(element_name.to_string());
1001
1002 if let Some(ns_all) = &self.current_ns_all {
1004 self.pending_namespace = Some(ns_all.clone());
1005 }
1006 }
1007
1008 Ok(())
1009 }
1010
1011 fn variant_metadata(
1012 &mut self,
1013 variant: &'static facet_core::Variant,
1014 ) -> Result<(), Self::Error> {
1015 if self.elements_stack.last() == Some(&true) {
1028 let element_name = variant
1030 .get_builtin_attr("rename")
1031 .and_then(|attr| attr.get_as::<&str>().copied())
1032 .unwrap_or(variant.name);
1033 self.pending_field = Some(element_name.to_string());
1034 self.skip_enum_wrapper = Some(variant.name.to_string());
1036 }
1037 Ok(())
1038 }
1039
1040 fn serialize_none(&mut self) -> Result<(), Self::Error> {
1043 self.pending_field = None;
1045 self.pending_namespace = None;
1046 self.pending_is_attribute = false;
1047 self.pending_is_text = false;
1048 Ok(())
1050 }
1051
1052 fn preferred_field_order(&self) -> facet_format::FieldOrdering {
1053 facet_format::FieldOrdering::AttributesFirst
1054 }
1055}
1056
1057pub fn to_vec<'facet, T>(value: &'_ T) -> Result<Vec<u8>, SerializeError<XmlSerializeError>>
1059where
1060 T: Facet<'facet> + ?Sized,
1061{
1062 to_vec_with_options(value, &SerializeOptions::default())
1063}
1064
1065pub fn to_vec_with_options<'facet, T>(
1067 value: &'_ T,
1068 options: &SerializeOptions,
1069) -> Result<Vec<u8>, SerializeError<XmlSerializeError>>
1070where
1071 T: Facet<'facet> + ?Sized,
1072{
1073 let mut serializer = XmlSerializer::with_options(options.clone());
1074 serialize_root(&mut serializer, Peek::new(value))?;
1075 Ok(serializer.finish())
1076}
1077
1078pub fn to_string<'facet, T>(value: &'_ T) -> Result<String, SerializeError<XmlSerializeError>>
1080where
1081 T: Facet<'facet> + ?Sized,
1082{
1083 let bytes = to_vec(value)?;
1084 Ok(String::from_utf8(bytes).expect("XmlSerializer produces valid UTF-8"))
1086}
1087
1088pub fn to_string_pretty<'facet, T>(
1090 value: &'_ T,
1091) -> Result<String, SerializeError<XmlSerializeError>>
1092where
1093 T: Facet<'facet> + ?Sized,
1094{
1095 to_string_with_options(value, &SerializeOptions::default().pretty())
1096}
1097
1098pub fn to_string_with_options<'facet, T>(
1100 value: &'_ T,
1101 options: &SerializeOptions,
1102) -> Result<String, SerializeError<XmlSerializeError>>
1103where
1104 T: Facet<'facet> + ?Sized,
1105{
1106 let bytes = to_vec_with_options(value, options)?;
1107 Ok(String::from_utf8(bytes).expect("XmlSerializer produces valid UTF-8"))
1109}
1110
1111fn escape_preserving_entities(s: &str, is_attribute: bool) -> String {
1118 let mut result = String::with_capacity(s.len());
1119 let chars: Vec<char> = s.chars().collect();
1120 let mut i = 0;
1121
1122 while i < chars.len() {
1123 let c = chars[i];
1124 match c {
1125 '<' => result.push_str("<"),
1126 '>' => result.push_str(">"),
1127 '"' if is_attribute => result.push_str("""),
1128 '&' => {
1129 if let Some(entity_len) = try_parse_entity_reference(&chars[i..]) {
1131 for j in 0..entity_len {
1133 result.push(chars[i + j]);
1134 }
1135 i += entity_len;
1136 continue;
1137 } else {
1138 result.push_str("&");
1140 }
1141 }
1142 _ => result.push(c),
1143 }
1144 i += 1;
1145 }
1146
1147 result
1148}
1149
1150fn try_parse_entity_reference(chars: &[char]) -> Option<usize> {
1158 if chars.is_empty() || chars[0] != '&' {
1159 return None;
1160 }
1161
1162 if chars.len() < 3 {
1164 return None;
1165 }
1166
1167 let mut len = 1; if chars[1] == '#' {
1170 len = 2;
1172
1173 if len < chars.len() && (chars[len] == 'x' || chars[len] == 'X') {
1174 len += 1;
1176 let start = len;
1177 while len < chars.len() && chars[len].is_ascii_hexdigit() {
1178 len += 1;
1179 }
1180 if len == start {
1182 return None;
1183 }
1184 } else {
1185 let start = len;
1187 while len < chars.len() && chars[len].is_ascii_digit() {
1188 len += 1;
1189 }
1190 if len == start {
1192 return None;
1193 }
1194 }
1195 } else {
1196 if !chars[len].is_ascii_alphabetic() && chars[len] != '_' {
1199 return None;
1200 }
1201 len += 1;
1202 while len < chars.len()
1203 && (chars[len].is_ascii_alphanumeric()
1204 || chars[len] == '_'
1205 || chars[len] == '-'
1206 || chars[len] == '.')
1207 {
1208 len += 1;
1209 }
1210 }
1211
1212 if len >= chars.len() || chars[len] != ';' {
1214 return None;
1215 }
1216
1217 Some(len + 1) }