1extern crate alloc;
2
3use alloc::borrow::Cow;
4use core::fmt::Debug;
5
6use facet_core::{ScalarType, StructKind};
7use facet_reflect::{HasFields as _, Peek, ReflectError};
8
9use crate::ScalarValue;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
13pub enum FieldOrdering {
14 #[default]
16 Declaration,
17 AttributesFirst,
19}
20
21pub trait FormatSerializer {
26 type Error: Debug;
28
29 fn begin_struct(&mut self) -> Result<(), Self::Error>;
31 fn field_key(&mut self, key: &str) -> Result<(), Self::Error>;
33 fn end_struct(&mut self) -> Result<(), Self::Error>;
35
36 fn begin_seq(&mut self) -> Result<(), Self::Error>;
38 fn end_seq(&mut self) -> Result<(), Self::Error>;
40
41 fn scalar(&mut self, scalar: ScalarValue<'_>) -> Result<(), Self::Error>;
43
44 fn field_metadata(&mut self, _field: &facet_reflect::FieldItem) -> Result<(), Self::Error> {
48 Ok(())
49 }
50
51 fn struct_metadata(&mut self, _shape: &facet_core::Shape) -> Result<(), Self::Error> {
55 Ok(())
56 }
57
58 fn preferred_field_order(&self) -> FieldOrdering {
62 FieldOrdering::Declaration
63 }
64
65 fn raw_serialize_shape(&self) -> Option<&'static facet_core::Shape> {
71 None
72 }
73
74 fn raw_scalar(&mut self, content: &str) -> Result<(), Self::Error> {
79 self.scalar(ScalarValue::Str(Cow::Borrowed(content)))
81 }
82
83 fn begin_seq_with_len(&mut self, _len: usize) -> Result<(), Self::Error> {
100 self.begin_seq()
101 }
102
103 fn typed_scalar(
113 &mut self,
114 scalar_type: ScalarType,
115 value: Peek<'_, '_>,
116 ) -> Result<(), Self::Error> {
117 let scalar = match scalar_type {
119 ScalarType::Unit => ScalarValue::Null,
120 ScalarType::Bool => ScalarValue::Bool(*value.get::<bool>().unwrap()),
121 ScalarType::Char => {
122 let c = *value.get::<char>().unwrap();
123 let mut buf = [0u8; 4];
124 ScalarValue::Str(Cow::Owned(c.encode_utf8(&mut buf).to_string()))
125 }
126 ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
127 ScalarValue::Str(Cow::Borrowed(value.as_str().unwrap()))
128 }
129 ScalarType::F32 => ScalarValue::F64(*value.get::<f32>().unwrap() as f64),
130 ScalarType::F64 => ScalarValue::F64(*value.get::<f64>().unwrap()),
131 ScalarType::U8 => ScalarValue::U64(*value.get::<u8>().unwrap() as u64),
132 ScalarType::U16 => ScalarValue::U64(*value.get::<u16>().unwrap() as u64),
133 ScalarType::U32 => ScalarValue::U64(*value.get::<u32>().unwrap() as u64),
134 ScalarType::U64 => ScalarValue::U64(*value.get::<u64>().unwrap()),
135 ScalarType::U128 => {
136 let n = *value.get::<u128>().unwrap();
137 ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&n)))
138 }
139 ScalarType::USize => ScalarValue::U64(*value.get::<usize>().unwrap() as u64),
140 ScalarType::I8 => ScalarValue::I64(*value.get::<i8>().unwrap() as i64),
141 ScalarType::I16 => ScalarValue::I64(*value.get::<i16>().unwrap() as i64),
142 ScalarType::I32 => ScalarValue::I64(*value.get::<i32>().unwrap() as i64),
143 ScalarType::I64 => ScalarValue::I64(*value.get::<i64>().unwrap()),
144 ScalarType::I128 => {
145 let n = *value.get::<i128>().unwrap();
146 ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&n)))
147 }
148 ScalarType::ISize => ScalarValue::I64(*value.get::<isize>().unwrap() as i64),
149 _ => {
150 if let Some(s) = value.as_str() {
152 ScalarValue::Str(Cow::Borrowed(s))
153 } else {
154 ScalarValue::Null
155 }
156 }
157 };
158 self.scalar(scalar)
159 }
160
161 fn begin_option_some(&mut self) -> Result<(), Self::Error> {
168 Ok(())
169 }
170
171 fn serialize_none(&mut self) -> Result<(), Self::Error> {
178 self.scalar(ScalarValue::Null)
179 }
180
181 fn begin_enum_variant(
191 &mut self,
192 _variant_index: usize,
193 _variant_name: &'static str,
194 ) -> Result<(), Self::Error> {
195 Ok(())
196 }
197}
198
199#[derive(Debug)]
201pub enum SerializeError<E: Debug> {
202 Backend(E),
204 Reflect(ReflectError),
206 Unsupported(Cow<'static, str>),
208 Internal(Cow<'static, str>),
210}
211
212impl<E: Debug> core::fmt::Display for SerializeError<E> {
213 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
214 match self {
215 SerializeError::Backend(_) => f.write_str("format serializer error"),
216 SerializeError::Reflect(err) => write!(f, "{err}"),
217 SerializeError::Unsupported(msg) => f.write_str(msg.as_ref()),
218 SerializeError::Internal(msg) => f.write_str(msg.as_ref()),
219 }
220 }
221}
222
223impl<E: Debug> std::error::Error for SerializeError<E> {}
224
225pub fn serialize_root<'mem, 'facet, S>(
227 serializer: &mut S,
228 value: Peek<'mem, 'facet>,
229) -> Result<(), SerializeError<S::Error>>
230where
231 S: FormatSerializer,
232{
233 shared_serialize(serializer, value)
234}
235
236fn sort_fields_if_needed<'mem, 'facet, S>(
238 serializer: &S,
239 fields: &mut alloc::vec::Vec<(facet_reflect::FieldItem, Peek<'mem, 'facet>)>,
240) where
241 S: FormatSerializer,
242{
243 if serializer.preferred_field_order() == FieldOrdering::AttributesFirst {
244 fields.sort_by_key(|(field_item, _)| {
245 if field_item
247 .field
248 .get_attr(Some("xml"), "attribute")
249 .is_some()
250 {
251 0 } else if field_item.field.get_attr(Some("xml"), "text").is_some() {
253 2 } else {
255 1 }
257 });
258 }
259}
260
261fn shared_serialize<'mem, 'facet, S>(
262 serializer: &mut S,
263 value: Peek<'mem, 'facet>,
264) -> Result<(), SerializeError<S::Error>>
265where
266 S: FormatSerializer,
267{
268 let value = deref_if_pointer(value);
270
271 if serializer.raw_serialize_shape() == Some(value.shape()) {
274 if let Ok(struct_) = value.into_struct()
277 && let Some((_field_item, inner_value)) = struct_.fields_for_serialize().next()
278 && let Some(s) = inner_value.as_str()
279 {
280 return serializer.raw_scalar(s).map_err(SerializeError::Backend);
281 }
282 return Err(SerializeError::Unsupported(Cow::Borrowed(
285 "raw capture type matched but could not extract inner string",
286 )));
287 }
288
289 let value = value.innermost_peek();
290
291 if let Some(proxy_def) = value.shape().proxy {
293 return serialize_via_proxy(serializer, value, proxy_def);
294 }
295
296 if let Some(scalar_type) = value.scalar_type() {
298 return serializer
299 .typed_scalar(scalar_type, value)
300 .map_err(SerializeError::Backend);
301 }
302
303 if let Ok(opt) = value.into_option() {
305 return match opt.value() {
306 Some(inner) => {
307 serializer
308 .begin_option_some()
309 .map_err(SerializeError::Backend)?;
310 shared_serialize(serializer, inner)
311 }
312 None => serializer.serialize_none().map_err(SerializeError::Backend),
313 };
314 }
315
316 if let Ok(list) = value.into_list_like() {
317 let items: alloc::vec::Vec<_> = list.iter().collect();
319 serializer
320 .begin_seq_with_len(items.len())
321 .map_err(SerializeError::Backend)?;
322 for item in items {
323 shared_serialize(serializer, item)?;
324 }
325 serializer.end_seq().map_err(SerializeError::Backend)?;
326 return Ok(());
327 }
328
329 if let Ok(map) = value.into_map() {
330 serializer.begin_struct().map_err(SerializeError::Backend)?;
331 for (key, val) in map.iter() {
332 let key_str = if let Some(s) = key.as_str() {
334 Cow::Borrowed(s)
335 } else {
336 Cow::Owned(alloc::format!("{:?}", key))
338 };
339 serializer
340 .field_key(&key_str)
341 .map_err(SerializeError::Backend)?;
342 shared_serialize(serializer, val)?;
343 }
344 serializer.end_struct().map_err(SerializeError::Backend)?;
345 return Ok(());
346 }
347
348 if let Ok(set) = value.into_set() {
349 let items: alloc::vec::Vec<_> = set.iter().collect();
351 serializer
352 .begin_seq_with_len(items.len())
353 .map_err(SerializeError::Backend)?;
354 for item in items {
355 shared_serialize(serializer, item)?;
356 }
357 serializer.end_seq().map_err(SerializeError::Backend)?;
358 return Ok(());
359 }
360
361 if let Ok(struct_) = value.into_struct() {
362 let kind = struct_.ty().kind;
363 if kind == StructKind::Tuple || kind == StructKind::TupleStruct {
364 let fields: alloc::vec::Vec<_> = struct_.fields_for_serialize().collect();
366 serializer
367 .begin_seq_with_len(fields.len())
368 .map_err(SerializeError::Backend)?;
369 for (_field_item, field_value) in fields {
370 shared_serialize(serializer, field_value)?;
371 }
372 serializer.end_seq().map_err(SerializeError::Backend)?;
373 } else {
374 serializer
376 .struct_metadata(value.shape())
377 .map_err(SerializeError::Backend)?;
378 serializer.begin_struct().map_err(SerializeError::Backend)?;
379
380 let mut fields: alloc::vec::Vec<_> = struct_.fields_for_serialize().collect();
382 sort_fields_if_needed(serializer, &mut fields);
383
384 for (field_item, field_value) in fields {
385 serializer
386 .field_metadata(&field_item)
387 .map_err(SerializeError::Backend)?;
388 serializer
389 .field_key(field_item.name)
390 .map_err(SerializeError::Backend)?;
391 shared_serialize(serializer, field_value)?;
392 }
393 serializer.end_struct().map_err(SerializeError::Backend)?;
394 }
395 return Ok(());
396 }
397
398 if let Ok(enum_) = value.into_enum() {
399 let variant = enum_.active_variant().map_err(|_| {
400 SerializeError::Unsupported(Cow::Borrowed("opaque enum layout is unsupported"))
401 })?;
402
403 let numeric = value.shape().is_numeric();
404 let untagged = value.shape().is_untagged();
405 let tag = value.shape().get_tag_attr();
406 let content = value.shape().get_content_attr();
407
408 if numeric {
409 return serialize_numeric_enum(serializer, variant);
410 }
411 if untagged {
412 return serialize_untagged_enum(serializer, enum_, variant);
413 }
414
415 match (tag, content) {
416 (Some(tag_key), None) => {
417 serializer.begin_struct().map_err(SerializeError::Backend)?;
419 serializer
420 .field_key(tag_key)
421 .map_err(SerializeError::Backend)?;
422 serializer
423 .scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
424 .map_err(SerializeError::Backend)?;
425
426 match variant.data.kind {
427 StructKind::Unit => {}
428 StructKind::Struct => {
429 let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
430 sort_fields_if_needed(serializer, &mut fields);
431 for (field_item, field_value) in fields {
432 serializer
433 .field_metadata(&field_item)
434 .map_err(SerializeError::Backend)?;
435 serializer
436 .field_key(field_item.name)
437 .map_err(SerializeError::Backend)?;
438 shared_serialize(serializer, field_value)?;
439 }
440 }
441 StructKind::TupleStruct | StructKind::Tuple => {
442 return Err(SerializeError::Unsupported(Cow::Borrowed(
443 "internally tagged tuple variants are not supported",
444 )));
445 }
446 }
447
448 serializer.end_struct().map_err(SerializeError::Backend)?;
449 return Ok(());
450 }
451 (Some(tag_key), Some(content_key)) => {
452 serializer.begin_struct().map_err(SerializeError::Backend)?;
454 serializer
455 .field_key(tag_key)
456 .map_err(SerializeError::Backend)?;
457 serializer
458 .scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
459 .map_err(SerializeError::Backend)?;
460
461 match variant.data.kind {
462 StructKind::Unit => {
463 }
465 StructKind::Struct => {
466 serializer
467 .field_key(content_key)
468 .map_err(SerializeError::Backend)?;
469 serializer.begin_struct().map_err(SerializeError::Backend)?;
470 let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
471 sort_fields_if_needed(serializer, &mut fields);
472 for (field_item, field_value) in fields {
473 serializer
474 .field_metadata(&field_item)
475 .map_err(SerializeError::Backend)?;
476 serializer
477 .field_key(field_item.name)
478 .map_err(SerializeError::Backend)?;
479 shared_serialize(serializer, field_value)?;
480 }
481 serializer.end_struct().map_err(SerializeError::Backend)?;
482 }
483 StructKind::TupleStruct | StructKind::Tuple => {
484 serializer
485 .field_key(content_key)
486 .map_err(SerializeError::Backend)?;
487
488 let field_count = variant.data.fields.len();
489 if field_count == 1 {
490 let inner = enum_
491 .field(0)
492 .map_err(|_| {
493 SerializeError::Internal(Cow::Borrowed(
494 "variant field lookup failed",
495 ))
496 })?
497 .ok_or(SerializeError::Internal(Cow::Borrowed(
498 "variant reported 1 field but field(0) returned None",
499 )))?;
500 shared_serialize(serializer, inner)?;
501 } else {
502 serializer.begin_seq().map_err(SerializeError::Backend)?;
503 for idx in 0..field_count {
504 let inner = enum_
505 .field(idx)
506 .map_err(|_| {
507 SerializeError::Internal(Cow::Borrowed(
508 "variant field lookup failed",
509 ))
510 })?
511 .ok_or(SerializeError::Internal(Cow::Borrowed(
512 "variant field missing while iterating tuple fields",
513 )))?;
514 shared_serialize(serializer, inner)?;
515 }
516 serializer.end_seq().map_err(SerializeError::Backend)?;
517 }
518 }
519 }
520
521 serializer.end_struct().map_err(SerializeError::Backend)?;
522 return Ok(());
523 }
524 (None, Some(_)) => {
525 return Err(SerializeError::Unsupported(Cow::Borrowed(
526 "adjacent content key set without tag key",
527 )));
528 }
529 (None, None) => {}
530 }
531
532 return match variant.data.kind {
534 StructKind::Unit => {
535 serializer
536 .scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
537 .map_err(SerializeError::Backend)?;
538 Ok(())
539 }
540 StructKind::TupleStruct | StructKind::Tuple => {
541 serializer.begin_struct().map_err(SerializeError::Backend)?;
542 serializer
543 .field_key(variant.name)
544 .map_err(SerializeError::Backend)?;
545
546 let field_count = variant.data.fields.len();
547 if field_count == 1 {
548 let inner = enum_
549 .field(0)
550 .map_err(|_| {
551 SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
552 })?
553 .ok_or(SerializeError::Internal(Cow::Borrowed(
554 "variant reported 1 field but field(0) returned None",
555 )))?;
556 shared_serialize(serializer, inner)?;
557 } else {
558 serializer.begin_seq().map_err(SerializeError::Backend)?;
559 for idx in 0..field_count {
560 let inner = enum_
561 .field(idx)
562 .map_err(|_| {
563 SerializeError::Internal(Cow::Borrowed(
564 "variant field lookup failed",
565 ))
566 })?
567 .ok_or(SerializeError::Internal(Cow::Borrowed(
568 "variant field missing while iterating tuple fields",
569 )))?;
570 shared_serialize(serializer, inner)?;
571 }
572 serializer.end_seq().map_err(SerializeError::Backend)?;
573 }
574
575 serializer.end_struct().map_err(SerializeError::Backend)?;
576 Ok(())
577 }
578 StructKind::Struct => {
579 serializer.begin_struct().map_err(SerializeError::Backend)?;
580 serializer
581 .field_key(variant.name)
582 .map_err(SerializeError::Backend)?;
583
584 serializer.begin_struct().map_err(SerializeError::Backend)?;
585 let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
586 sort_fields_if_needed(serializer, &mut fields);
587 for (field_item, field_value) in fields {
588 serializer
589 .field_metadata(&field_item)
590 .map_err(SerializeError::Backend)?;
591 serializer
592 .field_key(field_item.name)
593 .map_err(SerializeError::Backend)?;
594 shared_serialize(serializer, field_value)?;
595 }
596 serializer.end_struct().map_err(SerializeError::Backend)?;
597
598 serializer.end_struct().map_err(SerializeError::Backend)?;
599 Ok(())
600 }
601 };
602 }
603
604 Err(SerializeError::Unsupported(Cow::Borrowed(
605 "unsupported value kind for serialization",
606 )))
607}
608
609fn serialize_numeric_enum<S>(
610 serializer: &mut S,
611 variant: &'static facet_core::Variant,
612) -> Result<(), SerializeError<S::Error>>
613where
614 S: FormatSerializer,
615{
616 let discriminant = variant
617 .discriminant
618 .ok_or(SerializeError::Unsupported(Cow::Borrowed(
619 "Enum without a discriminant",
620 )))?;
621 serializer
622 .scalar(ScalarValue::I64(discriminant))
623 .map_err(SerializeError::Backend)
624}
625
626fn serialize_untagged_enum<'mem, 'facet, S>(
627 serializer: &mut S,
628 enum_: facet_reflect::PeekEnum<'mem, 'facet>,
629 variant: &'static facet_core::Variant,
630) -> Result<(), SerializeError<S::Error>>
631where
632 S: FormatSerializer,
633{
634 match variant.data.kind {
635 StructKind::Unit => {
636 if variant.name.eq_ignore_ascii_case("null") {
640 return serializer
641 .scalar(ScalarValue::Null)
642 .map_err(SerializeError::Backend);
643 }
644 serializer
645 .scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
646 .map_err(SerializeError::Backend)
647 }
648 StructKind::TupleStruct | StructKind::Tuple => {
649 let field_count = variant.data.fields.len();
650 if field_count == 1 {
651 let inner = enum_
652 .field(0)
653 .map_err(|_| {
654 SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
655 })?
656 .ok_or(SerializeError::Internal(Cow::Borrowed(
657 "variant reported 1 field but field(0) returned None",
658 )))?;
659 shared_serialize(serializer, inner)
660 } else {
661 serializer.begin_seq().map_err(SerializeError::Backend)?;
662 for idx in 0..field_count {
663 let inner = enum_
664 .field(idx)
665 .map_err(|_| {
666 SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
667 })?
668 .ok_or(SerializeError::Internal(Cow::Borrowed(
669 "variant field missing while iterating tuple fields",
670 )))?;
671 shared_serialize(serializer, inner)?;
672 }
673 serializer.end_seq().map_err(SerializeError::Backend)?;
674 Ok(())
675 }
676 }
677 StructKind::Struct => {
678 serializer.begin_struct().map_err(SerializeError::Backend)?;
679 let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
680 sort_fields_if_needed(serializer, &mut fields);
681 for (field_item, field_value) in fields {
682 serializer
683 .field_metadata(&field_item)
684 .map_err(SerializeError::Backend)?;
685 serializer
686 .field_key(field_item.name)
687 .map_err(SerializeError::Backend)?;
688 shared_serialize(serializer, field_value)?;
689 }
690 serializer.end_struct().map_err(SerializeError::Backend)?;
691 Ok(())
692 }
693 }
694}
695
696fn deref_if_pointer<'mem, 'facet>(peek: Peek<'mem, 'facet>) -> Peek<'mem, 'facet> {
698 if let Ok(ptr) = peek.into_pointer()
699 && let Some(target) = ptr.borrow_inner()
700 {
701 return deref_if_pointer(target);
702 }
703 peek
704}
705
706#[allow(unsafe_code)]
714fn serialize_via_proxy<'mem, 'facet, S>(
715 serializer: &mut S,
716 value: Peek<'mem, 'facet>,
717 proxy_def: &'static facet_core::ProxyDef,
718) -> Result<(), SerializeError<S::Error>>
719where
720 S: FormatSerializer,
721{
722 use facet_core::PtrUninit;
723
724 let proxy_shape = proxy_def.shape;
725 let proxy_layout = proxy_shape.layout.sized_layout().map_err(|_| {
726 SerializeError::Unsupported(Cow::Borrowed("proxy type must be sized for serialization"))
727 })?;
728
729 let proxy_mem = unsafe { alloc::alloc::alloc(proxy_layout) };
731 if proxy_mem.is_null() {
732 return Err(SerializeError::Internal(Cow::Borrowed(
733 "failed to allocate proxy memory",
734 )));
735 }
736
737 let proxy_uninit = PtrUninit::new(proxy_mem);
739 let convert_result = unsafe { (proxy_def.convert_out)(value.data(), proxy_uninit) };
740
741 let proxy_ptr = match convert_result {
742 Ok(ptr) => ptr,
743 Err(msg) => {
744 unsafe { alloc::alloc::dealloc(proxy_mem, proxy_layout) };
745 return Err(SerializeError::Unsupported(Cow::Owned(msg)));
746 }
747 };
748
749 let proxy_peek = unsafe { Peek::unchecked_new(proxy_ptr.as_const(), proxy_shape) };
751 let result = shared_serialize(serializer, proxy_peek);
752
753 unsafe {
755 let _ = proxy_shape.call_drop_in_place(proxy_ptr);
756 alloc::alloc::dealloc(proxy_mem, proxy_layout);
757 }
758
759 result
760}