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
84#[derive(Debug)]
86pub enum SerializeError<E: Debug> {
87 Backend(E),
89 Reflect(ReflectError),
91 Unsupported(Cow<'static, str>),
93 Internal(Cow<'static, str>),
95}
96
97impl<E: Debug> core::fmt::Display for SerializeError<E> {
98 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
99 match self {
100 SerializeError::Backend(_) => f.write_str("format serializer error"),
101 SerializeError::Reflect(err) => write!(f, "{err}"),
102 SerializeError::Unsupported(msg) => f.write_str(msg.as_ref()),
103 SerializeError::Internal(msg) => f.write_str(msg.as_ref()),
104 }
105 }
106}
107
108impl<E: Debug> std::error::Error for SerializeError<E> {}
109
110pub fn serialize_root<'mem, 'facet, S>(
112 serializer: &mut S,
113 value: Peek<'mem, 'facet>,
114) -> Result<(), SerializeError<S::Error>>
115where
116 S: FormatSerializer,
117{
118 shared_serialize(serializer, value)
119}
120
121fn sort_fields_if_needed<'mem, 'facet, S>(
123 serializer: &S,
124 fields: &mut alloc::vec::Vec<(facet_reflect::FieldItem, Peek<'mem, 'facet>)>,
125) where
126 S: FormatSerializer,
127{
128 if serializer.preferred_field_order() == FieldOrdering::AttributesFirst {
129 fields.sort_by_key(|(field_item, _)| {
130 if field_item
132 .field
133 .get_attr(Some("xml"), "attribute")
134 .is_some()
135 {
136 0 } else if field_item.field.get_attr(Some("xml"), "text").is_some() {
138 2 } else {
140 1 }
142 });
143 }
144}
145
146fn shared_serialize<'mem, 'facet, S>(
147 serializer: &mut S,
148 value: Peek<'mem, 'facet>,
149) -> Result<(), SerializeError<S::Error>>
150where
151 S: FormatSerializer,
152{
153 let value = deref_if_pointer(value);
155
156 if serializer.raw_serialize_shape() == Some(value.shape()) {
159 if let Ok(struct_) = value.into_struct()
162 && let Some((_field_item, inner_value)) = struct_.fields_for_serialize().next()
163 && let Some(s) = inner_value.as_str()
164 {
165 return serializer.raw_scalar(s).map_err(SerializeError::Backend);
166 }
167 return Err(SerializeError::Unsupported(Cow::Borrowed(
170 "raw capture type matched but could not extract inner string",
171 )));
172 }
173
174 let value = value.innermost_peek();
175
176 if let Some(proxy_def) = value.shape().proxy {
178 return serialize_via_proxy(serializer, value, proxy_def);
179 }
180
181 if let Some(scalar) = scalar_from_peek(value)? {
182 return serializer.scalar(scalar).map_err(SerializeError::Backend);
183 }
184
185 if let Ok(opt) = value.into_option() {
187 return match opt.value() {
188 Some(inner) => shared_serialize(serializer, inner),
189 None => serializer
190 .scalar(ScalarValue::Null)
191 .map_err(SerializeError::Backend),
192 };
193 }
194
195 if let Ok(list) = value.into_list_like() {
196 serializer.begin_seq().map_err(SerializeError::Backend)?;
197 for item in list.iter() {
198 shared_serialize(serializer, item)?;
199 }
200 serializer.end_seq().map_err(SerializeError::Backend)?;
201 return Ok(());
202 }
203
204 if let Ok(map) = value.into_map() {
205 serializer.begin_struct().map_err(SerializeError::Backend)?;
206 for (key, val) in map.iter() {
207 let key_str = if let Some(s) = key.as_str() {
209 Cow::Borrowed(s)
210 } else {
211 Cow::Owned(alloc::format!("{:?}", key))
213 };
214 serializer
215 .field_key(&key_str)
216 .map_err(SerializeError::Backend)?;
217 shared_serialize(serializer, val)?;
218 }
219 serializer.end_struct().map_err(SerializeError::Backend)?;
220 return Ok(());
221 }
222
223 if let Ok(set) = value.into_set() {
224 serializer.begin_seq().map_err(SerializeError::Backend)?;
225 for item in set.iter() {
226 shared_serialize(serializer, item)?;
227 }
228 serializer.end_seq().map_err(SerializeError::Backend)?;
229 return Ok(());
230 }
231
232 if let Ok(struct_) = value.into_struct() {
233 let kind = struct_.ty().kind;
234 if kind == StructKind::Tuple || kind == StructKind::TupleStruct {
235 serializer.begin_seq().map_err(SerializeError::Backend)?;
237 for (_field_item, field_value) in struct_.fields_for_serialize() {
238 shared_serialize(serializer, field_value)?;
239 }
240 serializer.end_seq().map_err(SerializeError::Backend)?;
241 } else {
242 serializer
244 .struct_metadata(value.shape())
245 .map_err(SerializeError::Backend)?;
246 serializer.begin_struct().map_err(SerializeError::Backend)?;
247
248 let mut fields: alloc::vec::Vec<_> = struct_.fields_for_serialize().collect();
250 sort_fields_if_needed(serializer, &mut fields);
251
252 for (field_item, field_value) in fields {
253 serializer
254 .field_metadata(&field_item)
255 .map_err(SerializeError::Backend)?;
256 serializer
257 .field_key(field_item.name)
258 .map_err(SerializeError::Backend)?;
259 shared_serialize(serializer, field_value)?;
260 }
261 serializer.end_struct().map_err(SerializeError::Backend)?;
262 }
263 return Ok(());
264 }
265
266 if let Ok(enum_) = value.into_enum() {
267 let variant = enum_.active_variant().map_err(|_| {
268 SerializeError::Unsupported(Cow::Borrowed("opaque enum layout is unsupported"))
269 })?;
270
271 let untagged = value.shape().is_untagged();
272 let tag = value.shape().get_tag_attr();
273 let content = value.shape().get_content_attr();
274
275 if untagged {
276 return serialize_untagged_enum(serializer, enum_, variant);
277 }
278
279 match (tag, content) {
280 (Some(tag_key), None) => {
281 serializer.begin_struct().map_err(SerializeError::Backend)?;
283 serializer
284 .field_key(tag_key)
285 .map_err(SerializeError::Backend)?;
286 serializer
287 .scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
288 .map_err(SerializeError::Backend)?;
289
290 match variant.data.kind {
291 StructKind::Unit => {}
292 StructKind::Struct => {
293 let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
294 sort_fields_if_needed(serializer, &mut fields);
295 for (field_item, field_value) in fields {
296 serializer
297 .field_metadata(&field_item)
298 .map_err(SerializeError::Backend)?;
299 serializer
300 .field_key(field_item.name)
301 .map_err(SerializeError::Backend)?;
302 shared_serialize(serializer, field_value)?;
303 }
304 }
305 StructKind::TupleStruct | StructKind::Tuple => {
306 return Err(SerializeError::Unsupported(Cow::Borrowed(
307 "internally tagged tuple variants are not supported",
308 )));
309 }
310 }
311
312 serializer.end_struct().map_err(SerializeError::Backend)?;
313 return Ok(());
314 }
315 (Some(tag_key), Some(content_key)) => {
316 serializer.begin_struct().map_err(SerializeError::Backend)?;
318 serializer
319 .field_key(tag_key)
320 .map_err(SerializeError::Backend)?;
321 serializer
322 .scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
323 .map_err(SerializeError::Backend)?;
324
325 match variant.data.kind {
326 StructKind::Unit => {
327 }
329 StructKind::Struct => {
330 serializer
331 .field_key(content_key)
332 .map_err(SerializeError::Backend)?;
333 serializer.begin_struct().map_err(SerializeError::Backend)?;
334 let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
335 sort_fields_if_needed(serializer, &mut fields);
336 for (field_item, field_value) in fields {
337 serializer
338 .field_metadata(&field_item)
339 .map_err(SerializeError::Backend)?;
340 serializer
341 .field_key(field_item.name)
342 .map_err(SerializeError::Backend)?;
343 shared_serialize(serializer, field_value)?;
344 }
345 serializer.end_struct().map_err(SerializeError::Backend)?;
346 }
347 StructKind::TupleStruct | StructKind::Tuple => {
348 serializer
349 .field_key(content_key)
350 .map_err(SerializeError::Backend)?;
351
352 let field_count = variant.data.fields.len();
353 if field_count == 1 {
354 let inner = enum_
355 .field(0)
356 .map_err(|_| {
357 SerializeError::Internal(Cow::Borrowed(
358 "variant field lookup failed",
359 ))
360 })?
361 .ok_or(SerializeError::Internal(Cow::Borrowed(
362 "variant reported 1 field but field(0) returned None",
363 )))?;
364 shared_serialize(serializer, inner)?;
365 } else {
366 serializer.begin_seq().map_err(SerializeError::Backend)?;
367 for idx in 0..field_count {
368 let inner = enum_
369 .field(idx)
370 .map_err(|_| {
371 SerializeError::Internal(Cow::Borrowed(
372 "variant field lookup failed",
373 ))
374 })?
375 .ok_or(SerializeError::Internal(Cow::Borrowed(
376 "variant field missing while iterating tuple fields",
377 )))?;
378 shared_serialize(serializer, inner)?;
379 }
380 serializer.end_seq().map_err(SerializeError::Backend)?;
381 }
382 }
383 }
384
385 serializer.end_struct().map_err(SerializeError::Backend)?;
386 return Ok(());
387 }
388 (None, Some(_)) => {
389 return Err(SerializeError::Unsupported(Cow::Borrowed(
390 "adjacent content key set without tag key",
391 )));
392 }
393 (None, None) => {}
394 }
395
396 return match variant.data.kind {
398 StructKind::Unit => {
399 serializer
400 .scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
401 .map_err(SerializeError::Backend)?;
402 Ok(())
403 }
404 StructKind::TupleStruct | StructKind::Tuple => {
405 serializer.begin_struct().map_err(SerializeError::Backend)?;
406 serializer
407 .field_key(variant.name)
408 .map_err(SerializeError::Backend)?;
409
410 let field_count = variant.data.fields.len();
411 if field_count == 1 {
412 let inner = enum_
413 .field(0)
414 .map_err(|_| {
415 SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
416 })?
417 .ok_or(SerializeError::Internal(Cow::Borrowed(
418 "variant reported 1 field but field(0) returned None",
419 )))?;
420 shared_serialize(serializer, inner)?;
421 } else {
422 serializer.begin_seq().map_err(SerializeError::Backend)?;
423 for idx in 0..field_count {
424 let inner = enum_
425 .field(idx)
426 .map_err(|_| {
427 SerializeError::Internal(Cow::Borrowed(
428 "variant field lookup failed",
429 ))
430 })?
431 .ok_or(SerializeError::Internal(Cow::Borrowed(
432 "variant field missing while iterating tuple fields",
433 )))?;
434 shared_serialize(serializer, inner)?;
435 }
436 serializer.end_seq().map_err(SerializeError::Backend)?;
437 }
438
439 serializer.end_struct().map_err(SerializeError::Backend)?;
440 Ok(())
441 }
442 StructKind::Struct => {
443 serializer.begin_struct().map_err(SerializeError::Backend)?;
444 serializer
445 .field_key(variant.name)
446 .map_err(SerializeError::Backend)?;
447
448 serializer.begin_struct().map_err(SerializeError::Backend)?;
449 let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
450 sort_fields_if_needed(serializer, &mut fields);
451 for (field_item, field_value) in fields {
452 serializer
453 .field_metadata(&field_item)
454 .map_err(SerializeError::Backend)?;
455 serializer
456 .field_key(field_item.name)
457 .map_err(SerializeError::Backend)?;
458 shared_serialize(serializer, field_value)?;
459 }
460 serializer.end_struct().map_err(SerializeError::Backend)?;
461
462 serializer.end_struct().map_err(SerializeError::Backend)?;
463 Ok(())
464 }
465 };
466 }
467
468 Err(SerializeError::Unsupported(Cow::Borrowed(
469 "unsupported value kind for serialization",
470 )))
471}
472
473fn serialize_untagged_enum<'mem, 'facet, S>(
474 serializer: &mut S,
475 enum_: facet_reflect::PeekEnum<'mem, 'facet>,
476 variant: &'static facet_core::Variant,
477) -> Result<(), SerializeError<S::Error>>
478where
479 S: FormatSerializer,
480{
481 match variant.data.kind {
482 StructKind::Unit => {
483 if variant.name.eq_ignore_ascii_case("null") {
487 return serializer
488 .scalar(ScalarValue::Null)
489 .map_err(SerializeError::Backend);
490 }
491 serializer
492 .scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
493 .map_err(SerializeError::Backend)
494 }
495 StructKind::TupleStruct | StructKind::Tuple => {
496 let field_count = variant.data.fields.len();
497 if field_count == 1 {
498 let inner = enum_
499 .field(0)
500 .map_err(|_| {
501 SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
502 })?
503 .ok_or(SerializeError::Internal(Cow::Borrowed(
504 "variant reported 1 field but field(0) returned None",
505 )))?;
506 shared_serialize(serializer, inner)
507 } else {
508 serializer.begin_seq().map_err(SerializeError::Backend)?;
509 for idx in 0..field_count {
510 let inner = enum_
511 .field(idx)
512 .map_err(|_| {
513 SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
514 })?
515 .ok_or(SerializeError::Internal(Cow::Borrowed(
516 "variant field missing while iterating tuple fields",
517 )))?;
518 shared_serialize(serializer, inner)?;
519 }
520 serializer.end_seq().map_err(SerializeError::Backend)?;
521 Ok(())
522 }
523 }
524 StructKind::Struct => {
525 serializer.begin_struct().map_err(SerializeError::Backend)?;
526 let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
527 sort_fields_if_needed(serializer, &mut fields);
528 for (field_item, field_value) in fields {
529 serializer
530 .field_metadata(&field_item)
531 .map_err(SerializeError::Backend)?;
532 serializer
533 .field_key(field_item.name)
534 .map_err(SerializeError::Backend)?;
535 shared_serialize(serializer, field_value)?;
536 }
537 serializer.end_struct().map_err(SerializeError::Backend)?;
538 Ok(())
539 }
540 }
541}
542
543fn deref_if_pointer<'mem, 'facet>(peek: Peek<'mem, 'facet>) -> Peek<'mem, 'facet> {
545 if let Ok(ptr) = peek.into_pointer()
546 && let Some(target) = ptr.borrow_inner()
547 {
548 return deref_if_pointer(target);
549 }
550 peek
551}
552
553#[allow(unsafe_code)]
561fn serialize_via_proxy<'mem, 'facet, S>(
562 serializer: &mut S,
563 value: Peek<'mem, 'facet>,
564 proxy_def: &'static facet_core::ProxyDef,
565) -> Result<(), SerializeError<S::Error>>
566where
567 S: FormatSerializer,
568{
569 use facet_core::PtrUninit;
570
571 let proxy_shape = proxy_def.shape;
572 let proxy_layout = proxy_shape.layout.sized_layout().map_err(|_| {
573 SerializeError::Unsupported(Cow::Borrowed("proxy type must be sized for serialization"))
574 })?;
575
576 let proxy_mem = unsafe { alloc::alloc::alloc(proxy_layout) };
578 if proxy_mem.is_null() {
579 return Err(SerializeError::Internal(Cow::Borrowed(
580 "failed to allocate proxy memory",
581 )));
582 }
583
584 let proxy_uninit = PtrUninit::new(proxy_mem);
586 let convert_result = unsafe { (proxy_def.convert_out)(value.data(), proxy_uninit) };
587
588 let proxy_ptr = match convert_result {
589 Ok(ptr) => ptr,
590 Err(msg) => {
591 unsafe { alloc::alloc::dealloc(proxy_mem, proxy_layout) };
592 return Err(SerializeError::Unsupported(Cow::Owned(msg)));
593 }
594 };
595
596 let proxy_peek = unsafe { Peek::unchecked_new(proxy_ptr.as_const(), proxy_shape) };
598 let result = shared_serialize(serializer, proxy_peek);
599
600 unsafe {
602 let _ = proxy_shape.call_drop_in_place(proxy_ptr);
603 alloc::alloc::dealloc(proxy_mem, proxy_layout);
604 }
605
606 result
607}
608
609fn scalar_from_peek<'mem, 'facet, E: Debug>(
610 value: Peek<'mem, 'facet>,
611) -> Result<Option<ScalarValue<'mem>>, SerializeError<E>> {
612 let Some(scalar_type) = value.scalar_type() else {
613 return Ok(None);
614 };
615
616 let scalar = match scalar_type {
617 ScalarType::Unit => ScalarValue::Null,
618 ScalarType::Bool => {
619 ScalarValue::Bool(*value.get::<bool>().map_err(SerializeError::Reflect)?)
620 }
621 ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
622 let Some(text) = value.as_str() else {
623 return Err(SerializeError::Internal(Cow::Borrowed(
624 "scalar_type indicated string but as_str returned None",
625 )));
626 };
627 ScalarValue::Str(Cow::Borrowed(text))
628 }
629 ScalarType::F32 => {
630 ScalarValue::F64(*value.get::<f32>().map_err(SerializeError::Reflect)? as f64)
631 }
632 ScalarType::F64 => ScalarValue::F64(*value.get::<f64>().map_err(SerializeError::Reflect)?),
633 ScalarType::U8 => {
634 ScalarValue::U64(*value.get::<u8>().map_err(SerializeError::Reflect)? as u64)
635 }
636 ScalarType::U16 => {
637 ScalarValue::U64(*value.get::<u16>().map_err(SerializeError::Reflect)? as u64)
638 }
639 ScalarType::U32 => {
640 ScalarValue::U64(*value.get::<u32>().map_err(SerializeError::Reflect)? as u64)
641 }
642 ScalarType::U64 => ScalarValue::U64(*value.get::<u64>().map_err(SerializeError::Reflect)?),
643 ScalarType::U128 => {
644 let n = *value.get::<u128>().map_err(SerializeError::Reflect)?;
645 ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&n)))
646 }
647 ScalarType::USize => {
648 ScalarValue::U64(*value.get::<usize>().map_err(SerializeError::Reflect)? as u64)
649 }
650 ScalarType::I8 => {
651 ScalarValue::I64(*value.get::<i8>().map_err(SerializeError::Reflect)? as i64)
652 }
653 ScalarType::I16 => {
654 ScalarValue::I64(*value.get::<i16>().map_err(SerializeError::Reflect)? as i64)
655 }
656 ScalarType::I32 => {
657 ScalarValue::I64(*value.get::<i32>().map_err(SerializeError::Reflect)? as i64)
658 }
659 ScalarType::I64 => ScalarValue::I64(*value.get::<i64>().map_err(SerializeError::Reflect)?),
660 ScalarType::I128 => {
661 let n = *value.get::<i128>().map_err(SerializeError::Reflect)?;
662 ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&n)))
663 }
664 ScalarType::ISize => {
665 ScalarValue::I64(*value.get::<isize>().map_err(SerializeError::Reflect)? as i64)
666 }
667 other => {
668 let _ = other;
669 return Ok(None);
670 }
671 };
672
673 Ok(Some(scalar))
674}