extern crate alloc;
use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt::Debug;
use core::fmt::Write as _;
use facet_core::{Def, DynDateTimeKind, DynValueKind, ScalarType, StructKind};
use facet_reflect::{HasFields as _, Peek, ReflectError};
use crate::ScalarValue;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FieldOrdering {
#[default]
Declaration,
AttributesFirst,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum StructFieldMode {
#[default]
Named,
Unnamed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum MapEncoding {
#[default]
Struct,
Pairs,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum EnumVariantEncoding {
#[default]
Tagged,
Index,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum DynamicValueEncoding {
#[default]
SelfDescribing,
Tagged,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DynamicValueTag {
Null,
Bool,
I64,
U64,
F64,
String,
Bytes,
Array,
Object,
DateTime,
}
pub trait FormatSerializer {
type Error: Debug;
fn begin_struct(&mut self) -> Result<(), Self::Error>;
fn field_key(&mut self, key: &str) -> Result<(), Self::Error>;
fn end_struct(&mut self) -> Result<(), Self::Error>;
fn begin_seq(&mut self) -> Result<(), Self::Error>;
fn end_seq(&mut self) -> Result<(), Self::Error>;
fn scalar(&mut self, scalar: ScalarValue<'_>) -> Result<(), Self::Error>;
fn field_metadata(&mut self, _field: &facet_reflect::FieldItem) -> Result<(), Self::Error> {
Ok(())
}
fn struct_metadata(&mut self, _shape: &facet_core::Shape) -> Result<(), Self::Error> {
Ok(())
}
fn variant_metadata(
&mut self,
_variant: &'static facet_core::Variant,
) -> Result<(), Self::Error> {
Ok(())
}
fn preferred_field_order(&self) -> FieldOrdering {
FieldOrdering::Declaration
}
fn struct_field_mode(&self) -> StructFieldMode {
StructFieldMode::Named
}
fn map_encoding(&self) -> MapEncoding {
MapEncoding::Struct
}
fn enum_variant_encoding(&self) -> EnumVariantEncoding {
EnumVariantEncoding::Tagged
}
fn dynamic_value_encoding(&self) -> DynamicValueEncoding {
DynamicValueEncoding::SelfDescribing
}
fn raw_serialize_shape(&self) -> Option<&'static facet_core::Shape> {
None
}
fn raw_scalar(&mut self, content: &str) -> Result<(), Self::Error> {
self.scalar(ScalarValue::Str(Cow::Borrowed(content)))
}
fn serialize_opaque_scalar(
&mut self,
_shape: &'static facet_core::Shape,
_value: Peek<'_, '_>,
) -> Result<bool, Self::Error> {
Ok(false)
}
fn dynamic_value_tag(&mut self, _tag: DynamicValueTag) -> Result<(), Self::Error> {
Ok(())
}
fn begin_seq_with_len(&mut self, _len: usize) -> Result<(), Self::Error> {
self.begin_seq()
}
fn begin_map_with_len(&mut self, _len: usize) -> Result<(), Self::Error> {
self.begin_struct()
}
fn end_map(&mut self) -> Result<(), Self::Error> {
self.end_struct()
}
fn typed_scalar(
&mut self,
scalar_type: ScalarType,
value: Peek<'_, '_>,
) -> Result<(), Self::Error> {
let scalar = match scalar_type {
ScalarType::Unit => ScalarValue::Null,
ScalarType::Bool => ScalarValue::Bool(*value.get::<bool>().unwrap()),
ScalarType::Char => ScalarValue::Char(*value.get::<char>().unwrap()),
ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
ScalarValue::Str(Cow::Borrowed(value.as_str().unwrap()))
}
ScalarType::F32 => ScalarValue::F64(*value.get::<f32>().unwrap() as f64),
ScalarType::F64 => ScalarValue::F64(*value.get::<f64>().unwrap()),
ScalarType::U8 => ScalarValue::U64(*value.get::<u8>().unwrap() as u64),
ScalarType::U16 => ScalarValue::U64(*value.get::<u16>().unwrap() as u64),
ScalarType::U32 => ScalarValue::U64(*value.get::<u32>().unwrap() as u64),
ScalarType::U64 => ScalarValue::U64(*value.get::<u64>().unwrap()),
ScalarType::U128 => {
let n = *value.get::<u128>().unwrap();
ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&n)))
}
ScalarType::USize => ScalarValue::U64(*value.get::<usize>().unwrap() as u64),
ScalarType::I8 => ScalarValue::I64(*value.get::<i8>().unwrap() as i64),
ScalarType::I16 => ScalarValue::I64(*value.get::<i16>().unwrap() as i64),
ScalarType::I32 => ScalarValue::I64(*value.get::<i32>().unwrap() as i64),
ScalarType::I64 => ScalarValue::I64(*value.get::<i64>().unwrap()),
ScalarType::I128 => {
let n = *value.get::<i128>().unwrap();
ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&n)))
}
ScalarType::ISize => ScalarValue::I64(*value.get::<isize>().unwrap() as i64),
#[cfg(feature = "net")]
ScalarType::IpAddr => {
let addr = *value.get::<core::net::IpAddr>().unwrap();
ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&addr)))
}
#[cfg(feature = "net")]
ScalarType::Ipv4Addr => {
let addr = *value.get::<core::net::Ipv4Addr>().unwrap();
ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&addr)))
}
#[cfg(feature = "net")]
ScalarType::Ipv6Addr => {
let addr = *value.get::<core::net::Ipv6Addr>().unwrap();
ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&addr)))
}
#[cfg(feature = "net")]
ScalarType::SocketAddr => {
let addr = *value.get::<core::net::SocketAddr>().unwrap();
ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&addr)))
}
_ => {
if let Some(s) = value.as_str() {
ScalarValue::Str(Cow::Borrowed(s))
} else {
ScalarValue::Null
}
}
};
self.scalar(scalar)
}
fn begin_option_some(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn serialize_none(&mut self) -> Result<(), Self::Error> {
self.scalar(ScalarValue::Null)
}
fn begin_enum_variant(
&mut self,
_variant_index: usize,
_variant_name: &'static str,
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug)]
pub enum SerializeError<E: Debug> {
Backend(E),
Reflect(ReflectError),
Unsupported(Cow<'static, str>),
Internal(Cow<'static, str>),
}
impl<E: Debug> core::fmt::Display for SerializeError<E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
SerializeError::Backend(_) => f.write_str("format serializer error"),
SerializeError::Reflect(err) => write!(f, "{err}"),
SerializeError::Unsupported(msg) => f.write_str(msg.as_ref()),
SerializeError::Internal(msg) => f.write_str(msg.as_ref()),
}
}
}
impl<E: Debug> std::error::Error for SerializeError<E> {}
pub fn serialize_root<'mem, 'facet, S>(
serializer: &mut S,
value: Peek<'mem, 'facet>,
) -> Result<(), SerializeError<S::Error>>
where
S: FormatSerializer,
{
shared_serialize(serializer, value)
}
fn sort_fields_if_needed<'mem, 'facet, S>(
serializer: &S,
fields: &mut alloc::vec::Vec<(facet_reflect::FieldItem, Peek<'mem, 'facet>)>,
) where
S: FormatSerializer,
{
if serializer.preferred_field_order() == FieldOrdering::AttributesFirst {
fields.sort_by_key(|(field_item, _)| {
match &field_item.field {
Some(field) if field.is_attribute() => 0, Some(field) if field.is_text() => 2, None => 0, _ => 1, }
});
}
}
fn shared_serialize<'mem, 'facet, S>(
serializer: &mut S,
value: Peek<'mem, 'facet>,
) -> Result<(), SerializeError<S::Error>>
where
S: FormatSerializer,
{
let value = deref_if_pointer(value);
if serializer.raw_serialize_shape() == Some(value.shape()) {
if let Ok(struct_) = value.into_struct()
&& let Some((_field_item, inner_value)) = struct_.fields_for_serialize().next()
&& let Some(s) = inner_value.as_str()
{
return serializer.raw_scalar(s).map_err(SerializeError::Backend);
}
return Err(SerializeError::Unsupported(Cow::Borrowed(
"raw capture type matched but could not extract inner string",
)));
}
if serializer
.serialize_opaque_scalar(value.shape(), value)
.map_err(SerializeError::Backend)?
{
return Ok(());
}
let value = value.innermost_peek();
if let Some(proxy_def) = value.shape().proxy {
return serialize_via_proxy(serializer, value, proxy_def);
}
if let Some(scalar_type) = value.scalar_type() {
return serializer
.typed_scalar(scalar_type, value)
.map_err(SerializeError::Backend);
}
if matches!(value.shape().def, Def::Scalar) && value.shape().vtable.has_display() {
use alloc::string::ToString;
let formatted = value.to_string();
return serializer
.scalar(ScalarValue::Str(Cow::Owned(formatted)))
.map_err(SerializeError::Backend);
}
if let Ok(opt) = value.into_option() {
return match opt.value() {
Some(inner) => {
serializer
.begin_option_some()
.map_err(SerializeError::Backend)?;
shared_serialize(serializer, inner)
}
None => serializer.serialize_none().map_err(SerializeError::Backend),
};
}
if let Ok(result) = value.into_result() {
let (variant_index, variant_name, inner) = if result.is_ok() {
(
0,
"Ok",
result.ok().ok_or(SerializeError::Internal(Cow::Borrowed(
"result reported Ok but value was missing",
)))?,
)
} else {
(
1,
"Err",
result.err().ok_or(SerializeError::Internal(Cow::Borrowed(
"result reported Err but value was missing",
)))?,
)
};
if serializer.enum_variant_encoding() == EnumVariantEncoding::Index {
serializer
.begin_enum_variant(variant_index, variant_name)
.map_err(SerializeError::Backend)?;
return shared_serialize(serializer, inner);
}
serializer.begin_struct().map_err(SerializeError::Backend)?;
serializer
.field_key(variant_name)
.map_err(SerializeError::Backend)?;
shared_serialize(serializer, inner)?;
serializer.end_struct().map_err(SerializeError::Backend)?;
return Ok(());
}
if let Ok(dynamic) = value.into_dynamic_value() {
return serialize_dynamic_value(serializer, dynamic);
}
match value.shape().def {
facet_core::Def::List(_) | facet_core::Def::Array(_) | facet_core::Def::Slice(_) => {
let list = value.into_list_like().map_err(SerializeError::Reflect)?;
let len = list.len();
match value.shape().def {
facet_core::Def::Array(_) => {
serializer.begin_seq().map_err(SerializeError::Backend)?
}
_ => serializer
.begin_seq_with_len(len)
.map_err(SerializeError::Backend)?,
};
for item in list.iter() {
shared_serialize(serializer, item)?;
}
serializer.end_seq().map_err(SerializeError::Backend)?;
return Ok(());
}
_ => {}
}
if let Ok(map) = value.into_map() {
let len = map.len();
match serializer.map_encoding() {
MapEncoding::Pairs => {
serializer
.begin_map_with_len(len)
.map_err(SerializeError::Backend)?;
for (key, val) in map.iter() {
shared_serialize(serializer, key)?;
shared_serialize(serializer, val)?;
}
serializer.end_map().map_err(SerializeError::Backend)?;
}
MapEncoding::Struct => {
serializer.begin_struct().map_err(SerializeError::Backend)?;
for (key, val) in map.iter() {
let key_str = if let Some(s) = key.as_str() {
Cow::Borrowed(s)
} else {
Cow::Owned(alloc::format!("{}", key))
};
serializer
.field_key(&key_str)
.map_err(SerializeError::Backend)?;
shared_serialize(serializer, val)?;
}
serializer.end_struct().map_err(SerializeError::Backend)?;
}
}
return Ok(());
}
if let Ok(set) = value.into_set() {
let len = set.len();
serializer
.begin_seq_with_len(len)
.map_err(SerializeError::Backend)?;
for item in set.iter() {
shared_serialize(serializer, item)?;
}
serializer.end_seq().map_err(SerializeError::Backend)?;
return Ok(());
}
if let Ok(struct_) = value.into_struct() {
let kind = struct_.ty().kind;
if kind == StructKind::Tuple || kind == StructKind::TupleStruct {
let fields: alloc::vec::Vec<_> = struct_.fields_for_serialize().collect();
serializer.begin_seq().map_err(SerializeError::Backend)?;
for (field_item, field_value) in fields {
if let Some(proxy_def) = field_item.field.and_then(|f| f.proxy()) {
serialize_via_proxy(serializer, field_value, proxy_def)?;
} else {
shared_serialize(serializer, field_value)?;
}
}
serializer.end_seq().map_err(SerializeError::Backend)?;
} else {
serializer
.struct_metadata(value.shape())
.map_err(SerializeError::Backend)?;
serializer.begin_struct().map_err(SerializeError::Backend)?;
let mut fields: alloc::vec::Vec<_> = struct_.fields_for_serialize().collect();
sort_fields_if_needed(serializer, &mut fields);
let field_mode = serializer.struct_field_mode();
for (field_item, field_value) in fields {
serializer
.field_metadata(&field_item)
.map_err(SerializeError::Backend)?;
if field_mode == StructFieldMode::Named {
serializer
.field_key(&field_item.name)
.map_err(SerializeError::Backend)?;
}
if let Some(proxy_def) = field_item.field.and_then(|f| f.proxy()) {
serialize_via_proxy(serializer, field_value, proxy_def)?;
} else {
shared_serialize(serializer, field_value)?;
}
}
serializer.end_struct().map_err(SerializeError::Backend)?;
}
return Ok(());
}
if let Ok(enum_) = value.into_enum() {
let variant = enum_.active_variant().map_err(|_| {
SerializeError::Unsupported(Cow::Borrowed("opaque enum layout is unsupported"))
})?;
serializer
.variant_metadata(variant)
.map_err(SerializeError::Backend)?;
if serializer.enum_variant_encoding() == EnumVariantEncoding::Index {
let variant_index = enum_.variant_index().map_err(|_| {
SerializeError::Unsupported(Cow::Borrowed("opaque enum layout is unsupported"))
})?;
serializer
.begin_enum_variant(variant_index, variant.name)
.map_err(SerializeError::Backend)?;
match variant.data.kind {
StructKind::Unit => return Ok(()),
StructKind::TupleStruct | StructKind::Tuple | StructKind::Struct => {
for (field_item, field_value) in enum_.fields_for_serialize() {
if let Some(proxy_def) = field_item.field.and_then(|f| f.proxy()) {
serialize_via_proxy(serializer, field_value, proxy_def)?;
} else {
shared_serialize(serializer, field_value)?;
}
}
return Ok(());
}
}
}
let numeric = value.shape().is_numeric();
let untagged = value.shape().is_untagged();
let tag = value.shape().get_tag_attr();
let content = value.shape().get_content_attr();
if numeric {
return serialize_numeric_enum(serializer, variant);
}
if untagged {
return serialize_untagged_enum(serializer, enum_, variant);
}
match (tag, content) {
(Some(tag_key), None) => {
serializer.begin_struct().map_err(SerializeError::Backend)?;
serializer
.field_key(tag_key)
.map_err(SerializeError::Backend)?;
serializer
.scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
.map_err(SerializeError::Backend)?;
match variant.data.kind {
StructKind::Unit => {}
StructKind::Struct => {
let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
sort_fields_if_needed(serializer, &mut fields);
let field_mode = serializer.struct_field_mode();
for (field_item, field_value) in fields {
serializer
.field_metadata(&field_item)
.map_err(SerializeError::Backend)?;
if field_mode == StructFieldMode::Named {
serializer
.field_key(&field_item.name)
.map_err(SerializeError::Backend)?;
}
if let Some(proxy_def) = field_item.field.and_then(|f| f.proxy()) {
serialize_via_proxy(serializer, field_value, proxy_def)?;
} else {
shared_serialize(serializer, field_value)?;
}
}
}
StructKind::TupleStruct | StructKind::Tuple => {
return Err(SerializeError::Unsupported(Cow::Borrowed(
"internally tagged tuple variants are not supported",
)));
}
}
serializer.end_struct().map_err(SerializeError::Backend)?;
return Ok(());
}
(Some(tag_key), Some(content_key)) => {
serializer.begin_struct().map_err(SerializeError::Backend)?;
serializer
.field_key(tag_key)
.map_err(SerializeError::Backend)?;
serializer
.scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
.map_err(SerializeError::Backend)?;
match variant.data.kind {
StructKind::Unit => {
}
StructKind::Struct => {
serializer
.field_key(content_key)
.map_err(SerializeError::Backend)?;
serializer.begin_struct().map_err(SerializeError::Backend)?;
let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
sort_fields_if_needed(serializer, &mut fields);
let field_mode = serializer.struct_field_mode();
for (field_item, field_value) in fields {
serializer
.field_metadata(&field_item)
.map_err(SerializeError::Backend)?;
if field_mode == StructFieldMode::Named {
serializer
.field_key(&field_item.name)
.map_err(SerializeError::Backend)?;
}
if let Some(proxy_def) = field_item.field.and_then(|f| f.proxy()) {
serialize_via_proxy(serializer, field_value, proxy_def)?;
} else {
shared_serialize(serializer, field_value)?;
}
}
serializer.end_struct().map_err(SerializeError::Backend)?;
}
StructKind::TupleStruct | StructKind::Tuple => {
serializer
.field_key(content_key)
.map_err(SerializeError::Backend)?;
let field_count = variant.data.fields.len();
if field_count == 1 {
let inner = enum_
.field(0)
.map_err(|_| {
SerializeError::Internal(Cow::Borrowed(
"variant field lookup failed",
))
})?
.ok_or(SerializeError::Internal(Cow::Borrowed(
"variant reported 1 field but field(0) returned None",
)))?;
shared_serialize(serializer, inner)?;
} else {
serializer.begin_seq().map_err(SerializeError::Backend)?;
for idx in 0..field_count {
let inner = enum_
.field(idx)
.map_err(|_| {
SerializeError::Internal(Cow::Borrowed(
"variant field lookup failed",
))
})?
.ok_or(SerializeError::Internal(Cow::Borrowed(
"variant field missing while iterating tuple fields",
)))?;
shared_serialize(serializer, inner)?;
}
serializer.end_seq().map_err(SerializeError::Backend)?;
}
}
}
serializer.end_struct().map_err(SerializeError::Backend)?;
return Ok(());
}
(None, Some(_)) => {
return Err(SerializeError::Unsupported(Cow::Borrowed(
"adjacent content key set without tag key",
)));
}
(None, None) => {}
}
return match variant.data.kind {
StructKind::Unit => {
serializer
.scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
.map_err(SerializeError::Backend)?;
Ok(())
}
StructKind::TupleStruct | StructKind::Tuple => {
serializer.begin_struct().map_err(SerializeError::Backend)?;
serializer
.field_key(variant.name)
.map_err(SerializeError::Backend)?;
let field_count = variant.data.fields.len();
if field_count == 1 {
let inner = enum_
.field(0)
.map_err(|_| {
SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
})?
.ok_or(SerializeError::Internal(Cow::Borrowed(
"variant reported 1 field but field(0) returned None",
)))?;
shared_serialize(serializer, inner)?;
} else {
serializer.begin_seq().map_err(SerializeError::Backend)?;
for idx in 0..field_count {
let inner = enum_
.field(idx)
.map_err(|_| {
SerializeError::Internal(Cow::Borrowed(
"variant field lookup failed",
))
})?
.ok_or(SerializeError::Internal(Cow::Borrowed(
"variant field missing while iterating tuple fields",
)))?;
shared_serialize(serializer, inner)?;
}
serializer.end_seq().map_err(SerializeError::Backend)?;
}
serializer.end_struct().map_err(SerializeError::Backend)?;
Ok(())
}
StructKind::Struct => {
serializer.begin_struct().map_err(SerializeError::Backend)?;
serializer
.field_key(variant.name)
.map_err(SerializeError::Backend)?;
serializer.begin_struct().map_err(SerializeError::Backend)?;
let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
sort_fields_if_needed(serializer, &mut fields);
let field_mode = serializer.struct_field_mode();
for (field_item, field_value) in fields {
serializer
.field_metadata(&field_item)
.map_err(SerializeError::Backend)?;
if field_mode == StructFieldMode::Named {
serializer
.field_key(&field_item.name)
.map_err(SerializeError::Backend)?;
}
if let Some(proxy_def) = field_item.field.and_then(|f| f.proxy()) {
serialize_via_proxy(serializer, field_value, proxy_def)?;
} else {
shared_serialize(serializer, field_value)?;
}
}
serializer.end_struct().map_err(SerializeError::Backend)?;
serializer.end_struct().map_err(SerializeError::Backend)?;
Ok(())
}
};
}
Err(SerializeError::Unsupported(Cow::Borrowed(
"unsupported value kind for serialization",
)))
}
fn serialize_dynamic_value<'mem, 'facet, S>(
serializer: &mut S,
dynamic: facet_reflect::PeekDynamicValue<'mem, 'facet>,
) -> Result<(), SerializeError<S::Error>>
where
S: FormatSerializer,
{
let tagged = serializer.dynamic_value_encoding() == DynamicValueEncoding::Tagged;
match dynamic.kind() {
DynValueKind::Null => {
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::Null)
.map_err(SerializeError::Backend)?;
}
serializer
.scalar(ScalarValue::Null)
.map_err(SerializeError::Backend)
}
DynValueKind::Bool => {
let value = dynamic.as_bool().ok_or_else(|| {
SerializeError::Internal(Cow::Borrowed("dynamic bool missing value"))
})?;
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::Bool)
.map_err(SerializeError::Backend)?;
}
serializer
.scalar(ScalarValue::Bool(value))
.map_err(SerializeError::Backend)
}
DynValueKind::Number => {
if let Some(n) = dynamic.as_i64() {
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::I64)
.map_err(SerializeError::Backend)?;
}
serializer
.scalar(ScalarValue::I64(n))
.map_err(SerializeError::Backend)
} else if let Some(n) = dynamic.as_u64() {
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::U64)
.map_err(SerializeError::Backend)?;
}
serializer
.scalar(ScalarValue::U64(n))
.map_err(SerializeError::Backend)
} else if let Some(n) = dynamic.as_f64() {
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::F64)
.map_err(SerializeError::Backend)?;
}
serializer
.scalar(ScalarValue::F64(n))
.map_err(SerializeError::Backend)
} else {
Err(SerializeError::Unsupported(Cow::Borrowed(
"dynamic number not representable",
)))
}
}
DynValueKind::String => {
let value = dynamic.as_str().ok_or_else(|| {
SerializeError::Internal(Cow::Borrowed("dynamic string missing value"))
})?;
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::String)
.map_err(SerializeError::Backend)?;
}
serializer
.scalar(ScalarValue::Str(Cow::Borrowed(value)))
.map_err(SerializeError::Backend)
}
DynValueKind::Bytes => {
let value = dynamic.as_bytes().ok_or_else(|| {
SerializeError::Internal(Cow::Borrowed("dynamic bytes missing value"))
})?;
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::Bytes)
.map_err(SerializeError::Backend)?;
}
serializer
.scalar(ScalarValue::Bytes(Cow::Borrowed(value)))
.map_err(SerializeError::Backend)
}
DynValueKind::Array => {
let len = dynamic.array_len().ok_or_else(|| {
SerializeError::Internal(Cow::Borrowed("dynamic array missing length"))
})?;
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::Array)
.map_err(SerializeError::Backend)?;
}
serializer
.begin_seq_with_len(len)
.map_err(SerializeError::Backend)?;
if let Some(iter) = dynamic.array_iter() {
for item in iter {
shared_serialize(serializer, item)?;
}
}
serializer.end_seq().map_err(SerializeError::Backend)
}
DynValueKind::Object => {
let len = dynamic.object_len().ok_or_else(|| {
SerializeError::Internal(Cow::Borrowed("dynamic object missing length"))
})?;
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::Object)
.map_err(SerializeError::Backend)?;
}
match serializer.map_encoding() {
MapEncoding::Pairs => {
serializer
.begin_map_with_len(len)
.map_err(SerializeError::Backend)?;
if let Some(iter) = dynamic.object_iter() {
for (key, value) in iter {
serializer
.scalar(ScalarValue::Str(Cow::Borrowed(key)))
.map_err(SerializeError::Backend)?;
shared_serialize(serializer, value)?;
}
}
serializer.end_map().map_err(SerializeError::Backend)
}
MapEncoding::Struct => {
serializer.begin_struct().map_err(SerializeError::Backend)?;
if let Some(iter) = dynamic.object_iter() {
for (key, value) in iter {
serializer.field_key(key).map_err(SerializeError::Backend)?;
shared_serialize(serializer, value)?;
}
}
serializer.end_struct().map_err(SerializeError::Backend)
}
}
}
DynValueKind::DateTime => {
let dt = dynamic.as_datetime().ok_or_else(|| {
SerializeError::Internal(Cow::Borrowed("dynamic datetime missing value"))
})?;
if tagged {
serializer
.dynamic_value_tag(DynamicValueTag::DateTime)
.map_err(SerializeError::Backend)?;
}
let s = format_dyn_datetime(dt);
serializer
.scalar(ScalarValue::Str(Cow::Owned(s)))
.map_err(SerializeError::Backend)
}
DynValueKind::QName | DynValueKind::Uuid => Err(SerializeError::Unsupported(
Cow::Borrowed("dynamic QName/Uuid serialization is not supported"),
)),
}
}
fn format_dyn_datetime(
(year, month, day, hour, minute, second, nanos, kind): (
i32,
u8,
u8,
u8,
u8,
u8,
u32,
DynDateTimeKind,
),
) -> String {
let mut out = String::new();
match kind {
DynDateTimeKind::Offset { offset_minutes } => {
let _ = write!(
out,
"{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
year, month, day, hour, minute, second
);
if nanos > 0 {
let _ = write!(out, ".{:09}", nanos);
}
if offset_minutes == 0 {
out.push('Z');
} else {
let sign = if offset_minutes >= 0 { '+' } else { '-' };
let abs = offset_minutes.unsigned_abs();
let _ = write!(out, "{}{:02}:{:02}", sign, abs / 60, abs % 60);
}
}
DynDateTimeKind::LocalDateTime => {
let _ = write!(
out,
"{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
year, month, day, hour, minute, second
);
if nanos > 0 {
let _ = write!(out, ".{:09}", nanos);
}
}
DynDateTimeKind::LocalDate => {
let _ = write!(out, "{:04}-{:02}-{:02}", year, month, day);
}
DynDateTimeKind::LocalTime => {
let _ = write!(out, "{:02}:{:02}:{:02}", hour, minute, second);
if nanos > 0 {
let _ = write!(out, ".{:09}", nanos);
}
}
}
out
}
fn serialize_numeric_enum<S>(
serializer: &mut S,
variant: &'static facet_core::Variant,
) -> Result<(), SerializeError<S::Error>>
where
S: FormatSerializer,
{
let discriminant = variant
.discriminant
.ok_or(SerializeError::Unsupported(Cow::Borrowed(
"Enum without a discriminant",
)))?;
serializer
.scalar(ScalarValue::I64(discriminant))
.map_err(SerializeError::Backend)
}
fn serialize_untagged_enum<'mem, 'facet, S>(
serializer: &mut S,
enum_: facet_reflect::PeekEnum<'mem, 'facet>,
variant: &'static facet_core::Variant,
) -> Result<(), SerializeError<S::Error>>
where
S: FormatSerializer,
{
match variant.data.kind {
StructKind::Unit => {
if variant.name.eq_ignore_ascii_case("null") {
return serializer
.scalar(ScalarValue::Null)
.map_err(SerializeError::Backend);
}
serializer
.scalar(ScalarValue::Str(Cow::Borrowed(variant.name)))
.map_err(SerializeError::Backend)
}
StructKind::TupleStruct | StructKind::Tuple => {
let field_count = variant.data.fields.len();
if field_count == 1 {
let inner = enum_
.field(0)
.map_err(|_| {
SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
})?
.ok_or(SerializeError::Internal(Cow::Borrowed(
"variant reported 1 field but field(0) returned None",
)))?;
shared_serialize(serializer, inner)
} else {
serializer.begin_seq().map_err(SerializeError::Backend)?;
for idx in 0..field_count {
let inner = enum_
.field(idx)
.map_err(|_| {
SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
})?
.ok_or(SerializeError::Internal(Cow::Borrowed(
"variant field missing while iterating tuple fields",
)))?;
shared_serialize(serializer, inner)?;
}
serializer.end_seq().map_err(SerializeError::Backend)?;
Ok(())
}
}
StructKind::Struct => {
serializer.begin_struct().map_err(SerializeError::Backend)?;
let mut fields: alloc::vec::Vec<_> = enum_.fields_for_serialize().collect();
sort_fields_if_needed(serializer, &mut fields);
for (field_item, field_value) in fields {
serializer
.field_metadata(&field_item)
.map_err(SerializeError::Backend)?;
serializer
.field_key(&field_item.name)
.map_err(SerializeError::Backend)?;
if let Some(proxy_def) = field_item.field.and_then(|f| f.proxy()) {
serialize_via_proxy(serializer, field_value, proxy_def)?;
} else {
shared_serialize(serializer, field_value)?;
}
}
serializer.end_struct().map_err(SerializeError::Backend)?;
Ok(())
}
}
}
fn deref_if_pointer<'mem, 'facet>(peek: Peek<'mem, 'facet>) -> Peek<'mem, 'facet> {
if let Ok(ptr) = peek.into_pointer()
&& let Some(target) = ptr.borrow_inner()
{
return deref_if_pointer(target);
}
peek
}
#[allow(unsafe_code)]
fn serialize_via_proxy<'mem, 'facet, S>(
serializer: &mut S,
value: Peek<'mem, 'facet>,
proxy_def: &'static facet_core::ProxyDef,
) -> Result<(), SerializeError<S::Error>>
where
S: FormatSerializer,
{
use facet_core::PtrUninit;
let proxy_shape = proxy_def.shape;
let proxy_layout = proxy_shape.layout.sized_layout().map_err(|_| {
SerializeError::Unsupported(Cow::Borrowed("proxy type must be sized for serialization"))
})?;
let proxy_mem = unsafe { alloc::alloc::alloc(proxy_layout) };
if proxy_mem.is_null() {
return Err(SerializeError::Internal(Cow::Borrowed(
"failed to allocate proxy memory",
)));
}
let proxy_uninit = PtrUninit::new(proxy_mem);
let convert_result = unsafe { (proxy_def.convert_out)(value.data(), proxy_uninit) };
let proxy_ptr = match convert_result {
Ok(ptr) => ptr,
Err(msg) => {
unsafe { alloc::alloc::dealloc(proxy_mem, proxy_layout) };
return Err(SerializeError::Unsupported(Cow::Owned(msg)));
}
};
let proxy_peek = unsafe { Peek::unchecked_new(proxy_ptr.as_const(), proxy_shape) };
let result = shared_serialize(serializer, proxy_peek);
unsafe {
let _ = proxy_shape.call_drop_in_place(proxy_ptr);
alloc::alloc::dealloc(proxy_mem, proxy_layout);
}
result
}