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::I64(v) => v.to_string(),
850 ScalarValue::U64(v) => v.to_string(),
851 ScalarValue::I128(v) => v.to_string(),
852 ScalarValue::U128(v) => v.to_string(),
853 ScalarValue::F64(v) => self.format_float(v),
854 ScalarValue::Str(s) => s.into_owned(),
855 ScalarValue::Bytes(_) => {
856 return Err(XmlSerializeError {
857 msg: "bytes serialization unsupported for xml",
858 });
859 }
860 };
861
862 self.pending_attributes.push((name, value, namespace));
863 self.pending_is_attribute = false;
864 return Ok(());
865 }
866
867 if self.pending_is_text {
869 self.pending_field = None;
871 self.pending_namespace = None;
872 self.pending_is_text = false;
873
874 self.flush_deferred_open_tag();
876 self.ensure_root_tag_written();
877
878 match scalar {
880 ScalarValue::Null => self.write_text_escaped("null"),
881 ScalarValue::Bool(v) => self.write_text_escaped(if v { "true" } else { "false" }),
882 ScalarValue::I64(v) => self.write_text_escaped(&v.to_string()),
883 ScalarValue::U64(v) => self.write_text_escaped(&v.to_string()),
884 ScalarValue::I128(v) => self.write_text_escaped(&v.to_string()),
885 ScalarValue::U128(v) => self.write_text_escaped(&v.to_string()),
886 ScalarValue::F64(v) => {
887 let formatted = self.format_float(v);
888 self.write_text_escaped(&formatted);
889 }
890 ScalarValue::Str(s) => self.write_text_escaped(&s),
891 ScalarValue::Bytes(_) => {
892 return Err(XmlSerializeError {
893 msg: "bytes serialization unsupported for xml",
894 });
895 }
896 }
897 return Ok(());
898 }
899
900 let close = self.open_value_element_if_needed()?;
902
903 match scalar {
904 ScalarValue::Null => {
905 self.write_text_escaped("null");
907 }
908 ScalarValue::Bool(v) => self.write_text_escaped(if v { "true" } else { "false" }),
909 ScalarValue::I64(v) => self.write_text_escaped(&v.to_string()),
910 ScalarValue::U64(v) => self.write_text_escaped(&v.to_string()),
911 ScalarValue::I128(v) => self.write_text_escaped(&v.to_string()),
912 ScalarValue::U128(v) => self.write_text_escaped(&v.to_string()),
913 ScalarValue::F64(v) => {
914 let formatted = self.format_float(v);
915 self.write_text_escaped(&formatted);
916 }
917 ScalarValue::Str(s) => self.write_text_escaped(&s),
918 ScalarValue::Bytes(_) => {
919 return Err(XmlSerializeError {
920 msg: "bytes serialization unsupported for xml",
921 });
922 }
923 }
924
925 if let Some(name) = close {
926 self.write_close_tag(&name, false);
928 self.write_newline();
929 }
930
931 Ok(())
932 }
933
934 fn field_metadata(&mut self, field: &facet_reflect::FieldItem) -> Result<(), Self::Error> {
935 let Some(field_def) = field.field else {
937 self.pending_is_attribute = true;
938 self.pending_is_text = false;
939 self.pending_is_elements = false;
940 return Ok(());
941 };
942
943 self.pending_is_attribute = field_def.get_attr(Some("xml"), "attribute").is_some();
945 self.pending_is_text = field_def.get_attr(Some("xml"), "text").is_some();
947 self.pending_is_elements = field_def.get_attr(Some("xml"), "elements").is_some();
949
950 if let Some(ns_attr) = field_def.get_attr(Some("xml"), "ns")
952 && let Some(ns_uri) = ns_attr.get_as::<&str>().copied()
953 {
954 self.pending_namespace = Some(ns_uri.to_string());
955 return Ok(());
956 }
957
958 if !self.pending_is_attribute
961 && !self.pending_is_text
962 && let Some(ns_all) = &self.current_ns_all
963 {
964 self.pending_namespace = Some(ns_all.clone());
965 }
966
967 Ok(())
968 }
969
970 fn struct_metadata(&mut self, shape: &facet_core::Shape) -> Result<(), Self::Error> {
971 self.current_ns_all = shape
973 .attributes
974 .iter()
975 .find(|attr| attr.ns == Some("xml") && attr.key == "ns_all")
976 .and_then(|attr| attr.get_as::<&str>().copied())
977 .map(String::from);
978
979 let element_name = shape
981 .get_builtin_attr_value::<&str>("rename")
982 .unwrap_or(shape.type_identifier);
983
984 if matches!(self.stack.last(), Some(Ctx::Root { kind: None })) {
986 self.root_element_name = Some(element_name.to_string());
987 }
988
989 if self.elements_stack.last() == Some(&true) && self.pending_field.is_none() {
991 self.pending_field = Some(element_name.to_string());
992
993 if let Some(ns_all) = &self.current_ns_all {
995 self.pending_namespace = Some(ns_all.clone());
996 }
997 }
998
999 Ok(())
1000 }
1001
1002 fn variant_metadata(
1003 &mut self,
1004 variant: &'static facet_core::Variant,
1005 ) -> Result<(), Self::Error> {
1006 if self.elements_stack.last() == Some(&true) {
1019 let element_name = variant
1021 .get_builtin_attr("rename")
1022 .and_then(|attr| attr.get_as::<&str>().copied())
1023 .unwrap_or(variant.name);
1024 self.pending_field = Some(element_name.to_string());
1025 self.skip_enum_wrapper = Some(variant.name.to_string());
1027 }
1028 Ok(())
1029 }
1030
1031 fn serialize_none(&mut self) -> Result<(), Self::Error> {
1034 self.pending_field = None;
1036 self.pending_namespace = None;
1037 self.pending_is_attribute = false;
1038 self.pending_is_text = false;
1039 Ok(())
1041 }
1042
1043 fn preferred_field_order(&self) -> facet_format::FieldOrdering {
1044 facet_format::FieldOrdering::AttributesFirst
1045 }
1046}
1047
1048pub fn to_vec<'facet, T>(value: &'_ T) -> Result<Vec<u8>, SerializeError<XmlSerializeError>>
1050where
1051 T: Facet<'facet> + ?Sized,
1052{
1053 to_vec_with_options(value, &SerializeOptions::default())
1054}
1055
1056pub fn to_vec_with_options<'facet, T>(
1058 value: &'_ T,
1059 options: &SerializeOptions,
1060) -> Result<Vec<u8>, SerializeError<XmlSerializeError>>
1061where
1062 T: Facet<'facet> + ?Sized,
1063{
1064 let mut serializer = XmlSerializer::with_options(options.clone());
1065 serialize_root(&mut serializer, Peek::new(value))?;
1066 Ok(serializer.finish())
1067}
1068
1069pub fn to_string<'facet, T>(value: &'_ T) -> Result<String, SerializeError<XmlSerializeError>>
1071where
1072 T: Facet<'facet> + ?Sized,
1073{
1074 let bytes = to_vec(value)?;
1075 Ok(String::from_utf8(bytes).expect("XmlSerializer produces valid UTF-8"))
1077}
1078
1079pub fn to_string_pretty<'facet, T>(
1081 value: &'_ T,
1082) -> Result<String, SerializeError<XmlSerializeError>>
1083where
1084 T: Facet<'facet> + ?Sized,
1085{
1086 to_string_with_options(value, &SerializeOptions::default().pretty())
1087}
1088
1089pub fn to_string_with_options<'facet, T>(
1091 value: &'_ T,
1092 options: &SerializeOptions,
1093) -> Result<String, SerializeError<XmlSerializeError>>
1094where
1095 T: Facet<'facet> + ?Sized,
1096{
1097 let bytes = to_vec_with_options(value, options)?;
1098 Ok(String::from_utf8(bytes).expect("XmlSerializer produces valid UTF-8"))
1100}
1101
1102fn escape_preserving_entities(s: &str, is_attribute: bool) -> String {
1109 let mut result = String::with_capacity(s.len());
1110 let chars: Vec<char> = s.chars().collect();
1111 let mut i = 0;
1112
1113 while i < chars.len() {
1114 let c = chars[i];
1115 match c {
1116 '<' => result.push_str("<"),
1117 '>' => result.push_str(">"),
1118 '"' if is_attribute => result.push_str("""),
1119 '&' => {
1120 if let Some(entity_len) = try_parse_entity_reference(&chars[i..]) {
1122 for j in 0..entity_len {
1124 result.push(chars[i + j]);
1125 }
1126 i += entity_len;
1127 continue;
1128 } else {
1129 result.push_str("&");
1131 }
1132 }
1133 _ => result.push(c),
1134 }
1135 i += 1;
1136 }
1137
1138 result
1139}
1140
1141fn try_parse_entity_reference(chars: &[char]) -> Option<usize> {
1149 if chars.is_empty() || chars[0] != '&' {
1150 return None;
1151 }
1152
1153 if chars.len() < 3 {
1155 return None;
1156 }
1157
1158 let mut len = 1; if chars[1] == '#' {
1161 len = 2;
1163
1164 if len < chars.len() && (chars[len] == 'x' || chars[len] == 'X') {
1165 len += 1;
1167 let start = len;
1168 while len < chars.len() && chars[len].is_ascii_hexdigit() {
1169 len += 1;
1170 }
1171 if len == start {
1173 return None;
1174 }
1175 } else {
1176 let start = len;
1178 while len < chars.len() && chars[len].is_ascii_digit() {
1179 len += 1;
1180 }
1181 if len == start {
1183 return None;
1184 }
1185 }
1186 } else {
1187 if !chars[len].is_ascii_alphabetic() && chars[len] != '_' {
1190 return None;
1191 }
1192 len += 1;
1193 while len < chars.len()
1194 && (chars[len].is_ascii_alphanumeric()
1195 || chars[len] == '_'
1196 || chars[len] == '-'
1197 || chars[len] == '.')
1198 {
1199 len += 1;
1200 }
1201 }
1202
1203 if len >= chars.len() || chars[len] != ';' {
1205 return None;
1206 }
1207
1208 Some(len + 1) }