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#[allow(dead_code)] const 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
50pub struct XmlSerializer {
57 out: Vec<u8>,
58 stack: Vec<Ctx>,
59 pending_field: Option<String>,
60 pending_namespace: Option<String>,
62 pending_is_attribute: bool,
64 pending_is_text: bool,
66 current_ns_all: Option<String>,
68 pending_attributes: Vec<(String, String, Option<String>)>,
70 item_tag: &'static str,
71 declared_namespaces: HashMap<String, String>,
73 next_ns_index: usize,
75 current_default_ns: Option<String>,
78 root_tag_written: bool,
80 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 self.ensure_root_tag_written();
109
110 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 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 if let Some(ns_uri) = element_ns {
133 if self.current_default_ns.as_deref() == Some(&ns_uri) {
134 self.out.extend_from_slice(element_name.as_bytes());
136 } else {
137 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 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 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 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 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 for b in attr_value.as_bytes() {
178 match *b {
179 b'&' => self.out.extend_from_slice(b"&"),
180 b'<' => self.out.extend_from_slice(b"<"),
181 b'>' => self.out.extend_from_slice(b">"),
182 b'"' => self.out.extend_from_slice(b"""),
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 if let Some(ns_uri) = self.pending_namespace.take() {
198 if self.current_default_ns.as_deref() == Some(&ns_uri) {
201 self.out.extend_from_slice(name.as_bytes());
203 } else {
204 let prefix = self.get_or_create_prefix(&ns_uri);
206
207 self.out.extend_from_slice(prefix.as_bytes());
209 self.out.push(b':');
210 self.out.extend_from_slice(name.as_bytes());
211
212 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 self.out.extend_from_slice(name.as_bytes());
222 }
223
224 let attrs: Vec<_> = self.pending_attributes.drain(..).collect();
227
228 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 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 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 for b in attr_value.as_bytes() {
255 match *b {
256 b'&' => self.out.extend_from_slice(b"&"),
257 b'<' => self.out.extend_from_slice(b"<"),
258 b'>' => self.out.extend_from_slice(b">"),
259 b'"' => self.out.extend_from_slice(b"""),
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"&"),
279 b'<' => self.out.extend_from_slice(b"<"),
280 b'>' => self.out.extend_from_slice(b">"),
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 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 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 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 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 for b in attr_value.as_bytes() {
327 match *b {
328 b'&' => self.out.extend_from_slice(b"&"),
329 b'<' => self.out.extend_from_slice(b"<"),
330 b'>' => self.out.extend_from_slice(b">"),
331 b'"' => self.out.extend_from_slice(b"""),
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 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 let full_name = if let Some(ns_uri) = self.pending_namespace.clone() {
359 if self.current_default_ns.as_deref() == Some(&ns_uri) {
360 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 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 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 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 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 fn get_or_create_prefix(&mut self, namespace_uri: &str) -> String {
444 if let Some(prefix) = self.declared_namespaces.get(namespace_uri) {
446 return prefix.clone();
447 }
448
449 let prefix = WELL_KNOWN_NAMESPACES
451 .iter()
452 .find(|(uri, _)| *uri == namespace_uri)
453 .map(|(_, prefix)| (*prefix).to_string())
454 .unwrap_or_else(|| {
455 let prefix = format!("ns{}", self.next_ns_index);
457 self.next_ns_index += 1;
458 prefix
459 });
460
461 let final_prefix = if self.declared_namespaces.values().any(|p| p == &prefix) {
463 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 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 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 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 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 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 self.pending_is_text {
610 self.pending_field = None;
612 self.pending_namespace = None;
613 self.pending_is_text = false;
614
615 self.flush_deferred_open_tag();
617 self.ensure_root_tag_written();
618
619 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 let close = self.open_value_element_if_needed()?;
640
641 match scalar {
642 ScalarValue::Null => {
643 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 self.pending_is_attribute = field.field.get_attr(Some("xml"), "attribute").is_some();
670 self.pending_is_text = field.field.get_attr(Some("xml"), "text").is_some();
672
673 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 !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 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 fn serialize_none(&mut self) -> Result<(), Self::Error> {
707 self.pending_field = None;
709 self.pending_namespace = None;
710 self.pending_is_attribute = false;
711 self.pending_is_text = false;
712 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}