Skip to main content

facet_format/
serializer.rs

1extern crate alloc;
2
3use alloc::borrow::Cow;
4use alloc::string::String;
5use core::fmt::Debug;
6use core::fmt::Write as _;
7
8use facet_core::{Def, DynDateTimeKind, DynValueKind, ScalarType, Shape, StructKind, Type};
9use facet_reflect::{HasFields as _, Peek, ReflectError};
10
11use crate::ScalarValue;
12
13/// Field ordering preference for serialization.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
15pub enum FieldOrdering {
16    /// Fields are serialized in declaration order (default).
17    #[default]
18    Declaration,
19}
20
21/// How struct fields should be serialized.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
23pub enum StructFieldMode {
24    /// Serialize fields with names/keys (default for text formats).
25    #[default]
26    Named,
27    /// Serialize fields in declaration order without names (binary formats).
28    Unnamed,
29}
30
31/// How map-like values should be serialized.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
33pub enum MapEncoding {
34    /// Serialize maps as objects/structs with string keys.
35    #[default]
36    Struct,
37    /// Serialize maps as key/value pairs (binary formats).
38    Pairs,
39}
40
41/// How enum variants should be serialized.
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
43pub enum EnumVariantEncoding {
44    /// Serialize enums using tag/field-name strategies (default for text formats).
45    #[default]
46    Tagged,
47    /// Serialize enums using a numeric variant index followed by fields (binary formats).
48    Index,
49}
50
51/// How dynamic values (e.g. `facet_value::Value`) should be encoded.
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
53pub enum DynamicValueEncoding {
54    /// Use the format's native self-describing encoding (default for JSON, MsgPack, etc.).
55    #[default]
56    SelfDescribing,
57    /// Use an explicit type tag before the dynamic value payload (binary formats).
58    Tagged,
59}
60
61/// Tag describing the concrete payload type for a dynamic value.
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum DynamicValueTag {
64    /// Null value.
65    Null,
66    /// Boolean value.
67    Bool,
68    /// Signed 64-bit integer.
69    I64,
70    /// Unsigned 64-bit integer.
71    U64,
72    /// 64-bit float.
73    F64,
74    /// UTF-8 string.
75    String,
76    /// Raw bytes.
77    Bytes,
78    /// Sequence/array.
79    Array,
80    /// Object/map.
81    Object,
82    /// Date/time value (encoded as string for tagged formats).
83    DateTime,
84}
85
86/// Low-level serializer interface implemented by each format backend.
87///
88/// This is intentionally event-ish: the shared serializer logic owns traversal
89/// (struct/enum/seq decisions), while formats own representation details.
90pub trait FormatSerializer {
91    /// Format-specific error type.
92    type Error: Debug;
93
94    /// Begin a map/object/struct.
95    fn begin_struct(&mut self) -> Result<(), Self::Error>;
96    /// Emit a field key within a struct.
97    fn field_key(&mut self, key: &str) -> Result<(), Self::Error>;
98    /// Emit a rich field key with optional tag and documentation.
99    ///
100    /// This is called when serializing map keys that have been extracted from
101    /// metadata containers (like `ObjectKey` with tag support).
102    ///
103    /// Default implementation ignores tag and doc, just emits the name.
104    /// Formats that support tags (like Styx) should override this.
105    fn emit_field_key(&mut self, key: &crate::FieldKey<'_>) -> Result<(), Self::Error> {
106        // Default: ignore tag and doc, just emit the name (empty string if None)
107        let name = key.name.as_deref().unwrap_or("");
108        self.field_key(name)
109    }
110    /// End a map/object/struct.
111    fn end_struct(&mut self) -> Result<(), Self::Error>;
112
113    /// Begin a sequence/array.
114    fn begin_seq(&mut self) -> Result<(), Self::Error>;
115    /// End a sequence/array.
116    fn end_seq(&mut self) -> Result<(), Self::Error>;
117
118    /// Emit a scalar value.
119    fn scalar(&mut self, scalar: ScalarValue<'_>) -> Result<(), Self::Error>;
120
121    /// Optional: Provide field metadata before field_key is called.
122    /// Default implementation does nothing.
123    fn field_metadata(&mut self, _field: &facet_reflect::FieldItem) -> Result<(), Self::Error> {
124        Ok(())
125    }
126
127    /// Optional: Provide field metadata with access to the field value.
128    ///
129    /// This is called before `field_key` and allows formats to inspect the field value
130    /// for metadata. This is particularly useful for metadata containers like `Documented<T>`
131    /// where doc comments are stored in the value, not the field definition.
132    ///
133    /// If this returns `Ok(true)`, the field key has been written and `field_key` will be skipped.
134    /// If this returns `Ok(false)`, normal field_key handling continues.
135    ///
136    /// Default implementation does nothing and returns `Ok(false)`.
137    fn field_metadata_with_value(
138        &mut self,
139        _field: &facet_reflect::FieldItem,
140        _value: Peek<'_, '_>,
141    ) -> Result<bool, Self::Error> {
142        Ok(false)
143    }
144
145    /// Optional: Provide struct/enum type metadata when beginning to serialize it.
146    /// Default implementation does nothing.
147    fn struct_metadata(&mut self, _shape: &facet_core::Shape) -> Result<(), Self::Error> {
148        Ok(())
149    }
150
151    /// Optional: Provide variant metadata before serializing an enum variant.
152    /// Default implementation does nothing.
153    fn variant_metadata(
154        &mut self,
155        _variant: &'static facet_core::Variant,
156    ) -> Result<(), Self::Error> {
157        Ok(())
158    }
159
160    /// Serialize a metadata container value.
161    ///
162    /// Metadata containers (structs with `#[facet(metadata_container)]`) have exactly
163    /// one non-metadata field (the actual value) and one or more metadata fields
164    /// (like doc comments or source spans).
165    ///
166    /// Formats that support metadata can override this to emit metadata in the
167    /// appropriate position. For example, Styx emits doc comments before the value:
168    ///
169    /// ```text
170    /// /// The port to listen on
171    /// port 8080
172    /// ```
173    ///
174    /// The format is responsible for:
175    /// 1. Extracting metadata fields (use `field.metadata_kind()` to identify them)
176    /// 2. Emitting metadata in the appropriate position
177    /// 3. Serializing the non-metadata field value
178    ///
179    /// Returns `Ok(true)` if handled, `Ok(false)` to fall back to default transparent
180    /// serialization (which just serializes the non-metadata field).
181    fn serialize_metadata_container(
182        &mut self,
183        _container: &facet_reflect::PeekStruct<'_, '_>,
184    ) -> Result<bool, Self::Error> {
185        Ok(false)
186    }
187
188    /// Preferred field ordering for this format.
189    /// Default is declaration order.
190    fn preferred_field_order(&self) -> FieldOrdering {
191        FieldOrdering::Declaration
192    }
193
194    /// Preferred struct field mode for this format.
195    fn struct_field_mode(&self) -> StructFieldMode {
196        StructFieldMode::Named
197    }
198
199    /// Preferred map encoding for this format.
200    fn map_encoding(&self) -> MapEncoding {
201        MapEncoding::Struct
202    }
203
204    /// Preferred enum variant encoding for this format.
205    fn enum_variant_encoding(&self) -> EnumVariantEncoding {
206        EnumVariantEncoding::Tagged
207    }
208
209    /// Whether this format is self-describing (includes type information).
210    ///
211    /// Self-describing formats (JSON, YAML, TOML) can deserialize without hints
212    /// and treat newtypes transparently. Non-self-describing formats (ASN.1,
213    /// postcard, msgpack) require structural hints and wrap newtypes.
214    ///
215    /// Default is `true` for text-based formats.
216    fn is_self_describing(&self) -> bool {
217        true
218    }
219
220    /// Preferred dynamic value encoding for this format.
221    fn dynamic_value_encoding(&self) -> DynamicValueEncoding {
222        DynamicValueEncoding::SelfDescribing
223    }
224
225    /// Returns the shape of the format's raw capture type for serialization.
226    ///
227    /// When serializing a value whose shape matches this, the serializer will
228    /// extract the inner string and call [`FormatSerializer::raw_scalar`] instead of normal
229    /// serialization.
230    fn raw_serialize_shape(&self) -> Option<&'static facet_core::Shape> {
231        None
232    }
233
234    /// Emit a raw scalar value (for RawJson, etc.) without any encoding/escaping.
235    ///
236    /// The content is the format-specific raw representation that should be
237    /// output directly.
238    fn raw_scalar(&mut self, content: &str) -> Result<(), Self::Error> {
239        // Default: treat as a regular string (formats should override this)
240        self.scalar(ScalarValue::Str(Cow::Borrowed(content)))
241    }
242
243    /// Serialize an opaque scalar type with a format-specific encoding.
244    ///
245    /// Returns `Ok(true)` if handled, `Ok(false)` to fall back to standard logic.
246    fn serialize_opaque_scalar(
247        &mut self,
248        _shape: &'static facet_core::Shape,
249        _value: Peek<'_, '_>,
250    ) -> Result<bool, Self::Error> {
251        Ok(false)
252    }
253
254    /// Emit a dynamic value type tag.
255    ///
256    /// Formats that use [`DynamicValueEncoding::Tagged`] should override this.
257    /// Self-describing formats can ignore it.
258    fn dynamic_value_tag(&mut self, _tag: DynamicValueTag) -> Result<(), Self::Error> {
259        Ok(())
260    }
261
262    // ─────────────────────────────────────────────────────────────────────────
263    // Binary format support methods
264    //
265    // The following methods enable proper serialization for binary formats like
266    // postcard that need length prefixes, type-precise encoding, and explicit
267    // discriminants. All have default implementations for backward compatibility
268    // with existing text-format serializers.
269    // ─────────────────────────────────────────────────────────────────────────
270
271    /// Begin a sequence with known length.
272    ///
273    /// Binary formats (postcard, msgpack) can use this to write a length prefix
274    /// before the elements. Text formats can ignore the length and just call
275    /// `begin_seq()`.
276    ///
277    /// Default: delegates to `begin_seq()`.
278    fn begin_seq_with_len(&mut self, _len: usize) -> Result<(), Self::Error> {
279        self.begin_seq()
280    }
281
282    /// Begin serializing a map with known length.
283    ///
284    /// Default: delegates to `begin_struct()` for formats that encode maps as objects.
285    fn begin_map_with_len(&mut self, _len: usize) -> Result<(), Self::Error> {
286        self.begin_struct()
287    }
288
289    /// End a map/object/struct.
290    ///
291    /// Default: delegates to `end_struct()`.
292    fn end_map(&mut self) -> Result<(), Self::Error> {
293        self.end_struct()
294    }
295
296    /// Serialize a map key in `MapEncoding::Struct` mode.
297    ///
298    /// This is called for each map key when using struct encoding. The default
299    /// implementation converts the key to a string (via `as_str()` or `Display`)
300    /// and calls `field_key()`.
301    ///
302    /// Formats can override this to handle special key types differently.
303    /// For example, Styx overrides this to serialize `Option::None` as `@`.
304    ///
305    /// Returns `Ok(true)` if handled, `Ok(false)` to use the default behavior.
306    fn serialize_map_key(&mut self, _key: Peek<'_, '_>) -> Result<bool, Self::Error> {
307        Ok(false)
308    }
309
310    /// Serialize a scalar with full type information.
311    ///
312    /// Binary formats need to encode different integer sizes differently:
313    /// - postcard: u8 as raw byte, u16+ as varint, signed use zigzag
314    /// - msgpack: different tags for different sizes
315    ///
316    /// Text formats can ignore the type and use the normalized `ScalarValue`.
317    ///
318    /// Default: normalizes to `ScalarValue` and calls `scalar()`.
319    fn typed_scalar(
320        &mut self,
321        scalar_type: ScalarType,
322        value: Peek<'_, '_>,
323    ) -> Result<(), Self::Error> {
324        // Default implementation: normalize to ScalarValue and call scalar()
325        let scalar = match scalar_type {
326            ScalarType::Unit => ScalarValue::Null,
327            ScalarType::Bool => ScalarValue::Bool(*value.get::<bool>().unwrap()),
328            ScalarType::Char => ScalarValue::Char(*value.get::<char>().unwrap()),
329            ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
330                ScalarValue::Str(Cow::Borrowed(value.as_str().unwrap()))
331            }
332            ScalarType::F32 => ScalarValue::F64(*value.get::<f32>().unwrap() as f64),
333            ScalarType::F64 => ScalarValue::F64(*value.get::<f64>().unwrap()),
334            ScalarType::U8 => ScalarValue::U64(*value.get::<u8>().unwrap() as u64),
335            ScalarType::U16 => ScalarValue::U64(*value.get::<u16>().unwrap() as u64),
336            ScalarType::U32 => ScalarValue::U64(*value.get::<u32>().unwrap() as u64),
337            ScalarType::U64 => ScalarValue::U64(*value.get::<u64>().unwrap()),
338            ScalarType::U128 => {
339                let n = *value.get::<u128>().unwrap();
340                ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&n)))
341            }
342            ScalarType::USize => ScalarValue::U64(*value.get::<usize>().unwrap() as u64),
343            ScalarType::I8 => ScalarValue::I64(*value.get::<i8>().unwrap() as i64),
344            ScalarType::I16 => ScalarValue::I64(*value.get::<i16>().unwrap() as i64),
345            ScalarType::I32 => ScalarValue::I64(*value.get::<i32>().unwrap() as i64),
346            ScalarType::I64 => ScalarValue::I64(*value.get::<i64>().unwrap()),
347            ScalarType::I128 => {
348                let n = *value.get::<i128>().unwrap();
349                ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&n)))
350            }
351            ScalarType::ISize => ScalarValue::I64(*value.get::<isize>().unwrap() as i64),
352            #[cfg(feature = "net")]
353            ScalarType::IpAddr => {
354                let addr = *value.get::<core::net::IpAddr>().unwrap();
355                ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&addr)))
356            }
357            #[cfg(feature = "net")]
358            ScalarType::Ipv4Addr => {
359                let addr = *value.get::<core::net::Ipv4Addr>().unwrap();
360                ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&addr)))
361            }
362            #[cfg(feature = "net")]
363            ScalarType::Ipv6Addr => {
364                let addr = *value.get::<core::net::Ipv6Addr>().unwrap();
365                ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&addr)))
366            }
367            #[cfg(feature = "net")]
368            ScalarType::SocketAddr => {
369                let addr = *value.get::<core::net::SocketAddr>().unwrap();
370                ScalarValue::Str(Cow::Owned(alloc::string::ToString::to_string(&addr)))
371            }
372            _ => {
373                // For unknown scalar types, try to get a string representation
374                if let Some(s) = value.as_str() {
375                    ScalarValue::Str(Cow::Borrowed(s))
376                } else {
377                    ScalarValue::Null
378                }
379            }
380        };
381        self.scalar(scalar)
382    }
383
384    /// Begin serializing `Option::Some(value)`.
385    ///
386    /// Binary formats like postcard write a `0x01` discriminant byte here.
387    /// Text formats typically don't need a prefix (they just serialize the value).
388    ///
389    /// Default: no-op (text formats).
390    fn begin_option_some(&mut self) -> Result<(), Self::Error> {
391        Ok(())
392    }
393
394    /// Serialize `Option::None`.
395    ///
396    /// Binary formats like postcard write a `0x00` discriminant byte.
397    /// Text formats typically emit `null`.
398    ///
399    /// Default: emits `ScalarValue::Null`.
400    fn serialize_none(&mut self) -> Result<(), Self::Error> {
401        self.scalar(ScalarValue::Null)
402    }
403
404    /// Begin an enum variant with its index and name.
405    ///
406    /// Binary formats like postcard write the variant index as a varint.
407    /// Text formats typically use the variant name as a key or value.
408    ///
409    /// This is called for externally tagged enums before the variant payload.
410    /// For untagged enums, this is not called.
411    ///
412    /// Default: no-op (text formats handle variants via field_key/scalar).
413    fn begin_enum_variant(
414        &mut self,
415        _variant_index: usize,
416        _variant_name: &'static str,
417    ) -> Result<(), Self::Error> {
418        Ok(())
419    }
420
421    /// Write a tag for an externally-tagged enum variant.
422    ///
423    /// Formats like Styx that use `@tag` syntax for enum variants should override
424    /// this to write their tag and return `Ok(true)`. The shared serializer will
425    /// then call the appropriate payload serialization method.
426    ///
427    /// If this returns `Ok(false)` (the default), the shared serializer uses
428    /// the standard externally-tagged representation: `{ "variant_name": payload }`.
429    ///
430    /// When returning `Ok(true)`:
431    /// - For unit variants, nothing more is written
432    /// - For newtype variants, the payload is serialized directly after
433    /// - For struct variants, begin_struct_after_tag is called for the payload
434    fn write_variant_tag(&mut self, _variant_name: &str) -> Result<bool, Self::Error> {
435        Ok(false)
436    }
437
438    /// Begin a struct directly after a variant tag (no separator).
439    ///
440    /// Called after `write_variant_tag` returns `Ok(true)` for struct variants.
441    /// Formats should write `{` without any preceding space/separator.
442    ///
443    /// Default: calls `begin_struct()`.
444    fn begin_struct_after_tag(&mut self) -> Result<(), Self::Error> {
445        self.begin_struct()
446    }
447
448    /// Begin a sequence directly after a variant tag (no separator).
449    ///
450    /// Called after `write_variant_tag` returns `Ok(true)` for tuple variants.
451    /// Formats should write `(` or `[` without any preceding space/separator.
452    ///
453    /// Default: calls `begin_seq()`.
454    fn begin_seq_after_tag(&mut self) -> Result<(), Self::Error> {
455        self.begin_seq()
456    }
457
458    /// Serialize a byte sequence (`Vec<u8>`, `&[u8]`, etc.) in bulk.
459    ///
460    /// For binary formats like postcard that store byte sequences as raw bytes
461    /// (varint length followed by raw data), this allows bulk writing instead
462    /// of element-by-element serialization.
463    ///
464    /// If the serializer handles this, it should write the bytes directly and
465    /// return `Ok(true)`. If it doesn't support this optimization, it should
466    /// return `Ok(false)` and the serializer will fall back to element-by-element
467    /// serialization.
468    ///
469    /// Returns `Ok(true)` if handled (bytes were written), `Ok(false)` otherwise.
470    fn serialize_byte_sequence(&mut self, _bytes: &[u8]) -> Result<bool, Self::Error> {
471        // Default: not supported, fall back to element-by-element
472        Ok(false)
473    }
474
475    /// Serialize a fixed-size byte array (`[u8; N]`) in bulk.
476    ///
477    /// Unlike `serialize_byte_sequence`, this does NOT write a length prefix
478    /// since the array size is known from the type.
479    ///
480    /// Returns `Ok(true)` if handled (bytes were written), `Ok(false)` otherwise.
481    fn serialize_byte_array(&mut self, _bytes: &[u8]) -> Result<bool, Self::Error> {
482        // Default: not supported, fall back to element-by-element
483        Ok(false)
484    }
485
486    /// Returns the format namespace for format-specific proxy resolution.
487    ///
488    /// When a field or container has format-specific proxies (e.g., `#[facet(xml::proxy = XmlProxy)]`),
489    /// this namespace is used to look up the appropriate proxy. If no namespace is returned,
490    /// only the format-agnostic proxy (`#[facet(proxy = ...)]`) is considered.
491    ///
492    /// Examples:
493    /// - XML serializer should return `Some("xml")`
494    /// - JSON serializer should return `Some("json")`
495    ///
496    /// Default: returns `None` (only format-agnostic proxies are used).
497    fn format_namespace(&self) -> Option<&'static str> {
498        None
499    }
500}
501
502/// Error produced by the shared serializer.
503#[derive(Debug)]
504pub enum SerializeError<E: Debug> {
505    /// Format backend error.
506    Backend(E),
507    /// Reflection failed while traversing the value.
508    Reflect(ReflectError),
509    /// Value can't be represented by the shared serializer.
510    Unsupported(Cow<'static, str>),
511    /// Internal invariant violation.
512    Internal(Cow<'static, str>),
513}
514
515impl<E: Debug> core::fmt::Display for SerializeError<E> {
516    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
517        match self {
518            SerializeError::Backend(_) => f.write_str("format serializer error"),
519            SerializeError::Reflect(err) => write!(f, "{err}"),
520            SerializeError::Unsupported(msg) => f.write_str(msg.as_ref()),
521            SerializeError::Internal(msg) => f.write_str(msg.as_ref()),
522        }
523    }
524}
525
526impl<E: Debug> std::error::Error for SerializeError<E> {}
527
528/// Serialize a root value using the shared traversal logic.
529pub fn serialize_root<'mem, 'facet, S>(
530    serializer: &mut S,
531    value: Peek<'mem, 'facet>,
532) -> Result<(), SerializeError<S::Error>>
533where
534    S: FormatSerializer,
535{
536    shared_serialize(serializer, value)
537}
538
539/// Helper to sort fields according to format preference (currently a no-op).
540fn sort_fields_if_needed<'mem, 'facet, S>(
541    _serializer: &S,
542    _fields: &mut alloc::vec::Vec<(facet_reflect::FieldItem, Peek<'mem, 'facet>)>,
543) where
544    S: FormatSerializer,
545{
546    // Currently only Declaration order is supported, which preserves the original order.
547}
548
549fn shared_serialize<'mem, 'facet, S>(
550    serializer: &mut S,
551    value: Peek<'mem, 'facet>,
552) -> Result<(), SerializeError<S::Error>>
553where
554    S: FormatSerializer,
555{
556    // Dereference pointers (Box, Arc, etc.) to get the underlying value
557    let value = deref_if_pointer(value);
558
559    // Check for raw serialization type (e.g., RawJson) BEFORE innermost_peek
560    // because innermost_peek might unwrap the type if it has .inner set
561    if serializer.raw_serialize_shape() == Some(value.shape()) {
562        // RawJson is a tuple struct with a single Cow<str> field
563        // Get the inner Cow<str> value via as_str on the inner.
564        // Use fields_for_binary_serialize to access the field directly without skip logic.
565        if let Ok(struct_) = value.into_struct()
566            && let Some((_field_item, inner_value)) = struct_.fields_for_binary_serialize().next()
567            && let Some(s) = inner_value.as_str()
568        {
569            return serializer.raw_scalar(s).map_err(SerializeError::Backend);
570        }
571        // If we get here, the raw shape matched but extraction failed
572        // This shouldn't happen for properly implemented raw types
573        return Err(SerializeError::Unsupported(Cow::Borrowed(
574            "raw capture type matched but could not extract inner string",
575        )));
576    }
577
578    if serializer
579        .serialize_opaque_scalar(value.shape(), value)
580        .map_err(SerializeError::Backend)?
581    {
582        return Ok(());
583    }
584
585    let value = value.innermost_peek();
586
587    // Check for metadata containers - serialize transparently through the inner value
588    // Metadata containers have exactly one non-metadata field that carries the actual value,
589    // while other fields (like doc comments) are metadata for formats that support it.
590    if value.shape().is_metadata_container()
591        && let Ok(struct_) = value.into_struct()
592    {
593        // Let the format handle metadata containers if it wants to (e.g., emit doc comments)
594        if serializer
595            .serialize_metadata_container(&struct_)
596            .map_err(SerializeError::Backend)?
597        {
598            return Ok(());
599        }
600        // Default: serialize transparently through the non-metadata field
601        for (field, field_value) in struct_.fields() {
602            if !field.is_metadata() {
603                return shared_serialize(serializer, field_value);
604            }
605        }
606    }
607
608    // Check for container-level proxy - serialize through the proxy type
609    // Format-specific proxies take precedence over format-agnostic proxies
610    if let Some(proxy_def) = value.shape().effective_proxy(serializer.format_namespace()) {
611        return serialize_via_proxy(serializer, value, proxy_def);
612    }
613
614    // Use typed_scalar for scalars - allows binary formats to encode precisely
615    if let Some(scalar_type) = value.scalar_type() {
616        return serializer
617            .typed_scalar(scalar_type, value)
618            .map_err(SerializeError::Backend);
619    }
620
621    // Fallback for Def::Scalar types with Display trait (e.g., SmolStr, SmartString, CompactString)
622    // These are string-like types that should serialize as strings
623    if matches!(value.shape().def, Def::Scalar) && value.shape().vtable.has_display() {
624        use alloc::string::ToString;
625        let formatted = value.to_string();
626        return serializer
627            .scalar(ScalarValue::Str(Cow::Owned(formatted)))
628            .map_err(SerializeError::Backend);
629    }
630
631    // Handle Option<T> - use begin_option_some/serialize_none for binary formats
632    if let Ok(opt) = value.into_option() {
633        return match opt.value() {
634            Some(inner) => {
635                serializer
636                    .begin_option_some()
637                    .map_err(SerializeError::Backend)?;
638                shared_serialize(serializer, inner)
639            }
640            None => serializer.serialize_none().map_err(SerializeError::Backend),
641        };
642    }
643
644    if let Ok(result) = value.into_result() {
645        let (variant_index, variant_name, inner) = if result.is_ok() {
646            (
647                0,
648                "Ok",
649                result.ok().ok_or(SerializeError::Internal(Cow::Borrowed(
650                    "result reported Ok but value was missing",
651                )))?,
652            )
653        } else {
654            (
655                1,
656                "Err",
657                result.err().ok_or(SerializeError::Internal(Cow::Borrowed(
658                    "result reported Err but value was missing",
659                )))?,
660            )
661        };
662
663        if serializer.enum_variant_encoding() == EnumVariantEncoding::Index {
664            serializer
665                .begin_enum_variant(variant_index, variant_name)
666                .map_err(SerializeError::Backend)?;
667            return shared_serialize(serializer, inner);
668        }
669
670        // Externally tagged representation for non-index encodings.
671        serializer.begin_struct().map_err(SerializeError::Backend)?;
672        serializer
673            .field_key(variant_name)
674            .map_err(SerializeError::Backend)?;
675        shared_serialize(serializer, inner)?;
676        serializer.end_struct().map_err(SerializeError::Backend)?;
677        return Ok(());
678    }
679
680    if let Ok(dynamic) = value.into_dynamic_value() {
681        return serialize_dynamic_value(serializer, dynamic);
682    }
683
684    match value.shape().def {
685        facet_core::Def::List(_) | facet_core::Def::Array(_) | facet_core::Def::Slice(_) => {
686            let list = value.into_list_like().map_err(SerializeError::Reflect)?;
687            let len = list.len();
688
689            // Check if this is a byte sequence - if so, try bulk serialization
690            if let Some(bytes) = list.as_bytes() {
691                let handled = match value.shape().def {
692                    // Arrays have no length prefix
693                    facet_core::Def::Array(_) => serializer
694                        .serialize_byte_array(bytes)
695                        .map_err(SerializeError::Backend)?,
696                    // Lists and slices have a length prefix
697                    _ => serializer
698                        .serialize_byte_sequence(bytes)
699                        .map_err(SerializeError::Backend)?,
700                };
701                if handled {
702                    return Ok(());
703                }
704            }
705            // Fall through to element-by-element if not handled
706
707            match value.shape().def {
708                facet_core::Def::Array(_) => {
709                    serializer.begin_seq().map_err(SerializeError::Backend)?
710                }
711                _ => serializer
712                    .begin_seq_with_len(len)
713                    .map_err(SerializeError::Backend)?,
714            };
715            for item in list.iter() {
716                shared_serialize(serializer, item)?;
717            }
718            serializer.end_seq().map_err(SerializeError::Backend)?;
719            return Ok(());
720        }
721        _ => {}
722    }
723
724    if let Ok(map) = value.into_map() {
725        let len = map.len();
726        match serializer.map_encoding() {
727            MapEncoding::Pairs => {
728                serializer
729                    .begin_map_with_len(len)
730                    .map_err(SerializeError::Backend)?;
731                for (key, val) in map.iter() {
732                    shared_serialize(serializer, key)?;
733                    shared_serialize(serializer, val)?;
734                }
735                serializer.end_map().map_err(SerializeError::Backend)?;
736            }
737            MapEncoding::Struct => {
738                serializer.begin_struct().map_err(SerializeError::Backend)?;
739                for (key, val) in map.iter() {
740                    // Let format handle special key types first
741                    if !serializer
742                        .serialize_map_key(key)
743                        .map_err(SerializeError::Backend)?
744                    {
745                        // Default: convert the key to a string for the field name
746                        let key_str = if let Some(s) = key.as_str() {
747                            Cow::Borrowed(s)
748                        } else {
749                            // For non-string keys, use Display format (not Debug, which adds quotes)
750                            Cow::Owned(alloc::format!("{}", key))
751                        };
752                        serializer
753                            .field_key(&key_str)
754                            .map_err(SerializeError::Backend)?;
755                    }
756                    shared_serialize(serializer, val)?;
757                }
758                serializer.end_struct().map_err(SerializeError::Backend)?;
759            }
760        }
761        return Ok(());
762    }
763
764    if let Ok(set) = value.into_set() {
765        // Use begin_seq_with_len for binary formats that need length prefixes
766        let len = set.len();
767        serializer
768            .begin_seq_with_len(len)
769            .map_err(SerializeError::Backend)?;
770        for item in set.iter() {
771            shared_serialize(serializer, item)?;
772        }
773        serializer.end_seq().map_err(SerializeError::Backend)?;
774        return Ok(());
775    }
776
777    if let Ok(struct_) = value.into_struct() {
778        let kind = struct_.ty().kind;
779        let field_mode = serializer.struct_field_mode();
780
781        if kind == StructKind::Tuple || kind == StructKind::TupleStruct {
782            // Special case: transparent newtypes (marked with #[facet(transparent)] or
783            // #[repr(transparent)]) serialize as their inner value without wrapping.
784            let fields: alloc::vec::Vec<_> = struct_.fields_for_binary_serialize().collect();
785            let is_transparent = value.shape().is_transparent() && fields.len() == 1;
786
787            if is_transparent {
788                // Serialize the single field directly without array wrapper
789                let (field_item, field_value) = &fields[0];
790                if let Some(proxy_def) = field_item
791                    .field
792                    .and_then(|f| f.effective_proxy(serializer.format_namespace()))
793                {
794                    serialize_via_proxy(serializer, *field_value, proxy_def)?;
795                } else {
796                    shared_serialize(serializer, *field_value)?;
797                }
798            } else {
799                // Serialize tuples as arrays without length prefixes.
800                // Tuples are positional, so use binary serialize to avoid skip predicates.
801                serializer.begin_seq().map_err(SerializeError::Backend)?;
802                for (field_item, field_value) in fields {
803                    // Check for field-level proxy
804                    if let Some(proxy_def) = field_item
805                        .field
806                        .and_then(|f| f.effective_proxy(serializer.format_namespace()))
807                    {
808                        serialize_via_proxy(serializer, field_value, proxy_def)?;
809                    } else {
810                        shared_serialize(serializer, field_value)?;
811                    }
812                }
813                serializer.end_seq().map_err(SerializeError::Backend)?;
814            }
815        } else {
816            // Regular structs as objects
817            serializer
818                .struct_metadata(value.shape())
819                .map_err(SerializeError::Backend)?;
820            serializer.begin_struct().map_err(SerializeError::Backend)?;
821
822            // Collect fields and sort according to format preference.
823            // For binary formats (Unnamed), use fields_for_binary_serialize to avoid
824            // skip predicates that would break positional deserialization.
825            let mut fields: alloc::vec::Vec<_> = if field_mode == StructFieldMode::Unnamed {
826                struct_.fields_for_binary_serialize().collect()
827            } else {
828                struct_.fields_for_serialize().collect()
829            };
830
831            sort_fields_if_needed(serializer, &mut fields);
832
833            for (field_item, field_value) in fields {
834                // Check for flattened internally-tagged enum
835                // For these, we need to emit the tag field and flatten the content
836                if field_item.flattened
837                    && let Some(field) = field_item.field
838                    && let shape = field.shape()
839                    && let Some(tag_key) = shape.get_tag_attr()
840                    && shape.get_content_attr().is_none()
841                {
842                    // Internally-tagged: has tag but no content attribute
843                    let variant_name = field_item.effective_name();
844
845                    // Emit the tag field
846                    if field_mode == StructFieldMode::Named {
847                        serializer
848                            .field_key(tag_key)
849                            .map_err(SerializeError::Backend)?;
850                    }
851                    serializer
852                        .scalar(ScalarValue::Str(Cow::Borrowed(variant_name)))
853                        .map_err(SerializeError::Backend)?;
854
855                    // Emit the content fields (flattened)
856                    // For newtype variants, field_value is the inner struct
857                    // For struct variants, field_value is the enum itself
858                    if let Ok(inner_struct) = field_value.into_struct() {
859                        // Newtype variant - iterate inner struct's fields
860                        for (inner_item, inner_value) in inner_struct.fields_for_serialize() {
861                            if field_mode == StructFieldMode::Named {
862                                serializer
863                                    .field_key(inner_item.effective_name())
864                                    .map_err(SerializeError::Backend)?;
865                            }
866                            if let Some(proxy_def) = inner_item
867                                .field
868                                .and_then(|f| f.effective_proxy(serializer.format_namespace()))
869                            {
870                                serialize_via_proxy(serializer, inner_value, proxy_def)?;
871                            } else {
872                                shared_serialize(serializer, inner_value)?;
873                            }
874                        }
875                    } else if let Ok(enum_peek) = field_value.into_enum() {
876                        // Struct variant - iterate enum's fields (the variant's fields)
877                        for (inner_item, inner_value) in enum_peek.fields_for_serialize() {
878                            if field_mode == StructFieldMode::Named {
879                                serializer
880                                    .field_key(inner_item.effective_name())
881                                    .map_err(SerializeError::Backend)?;
882                            }
883                            if let Some(proxy_def) = inner_item
884                                .field
885                                .and_then(|f| f.effective_proxy(serializer.format_namespace()))
886                            {
887                                serialize_via_proxy(serializer, inner_value, proxy_def)?;
888                            } else {
889                                shared_serialize(serializer, inner_value)?;
890                            }
891                        }
892                    } else if matches!(field_value.shape().ty, Type::Primitive(_)) {
893                        // Scalar/primitive payload (e.g., A(i32))
894                        // Internally-tagged enums cannot flatten scalar payloads -
895                        // there's no field name to use for the value.
896                        // Use #[facet(content = "...")] for adjacently-tagged representation.
897                        return Err(SerializeError::Unsupported(
898                            "internally-tagged enum with scalar newtype payload cannot be \
899                             flattened; use #[facet(content = \"...\")] for adjacently-tagged \
900                             representation"
901                                .into(),
902                        ));
903                    }
904                    // Unit variants have no content fields to emit
905                    continue;
906                }
907
908                // Let format handle field metadata with value access (for metadata containers)
909                let key_written = serializer
910                    .field_metadata_with_value(&field_item, field_value)
911                    .map_err(SerializeError::Backend)?;
912                if !key_written {
913                    serializer
914                        .field_metadata(&field_item)
915                        .map_err(SerializeError::Backend)?;
916                    if field_mode == StructFieldMode::Named {
917                        serializer
918                            .field_key(field_item.effective_name())
919                            .map_err(SerializeError::Backend)?;
920                    }
921                }
922                // Check for field-level proxy
923                if let Some(proxy_def) = field_item
924                    .field
925                    .and_then(|f| f.effective_proxy(serializer.format_namespace()))
926                {
927                    serialize_via_proxy(serializer, field_value, proxy_def)?;
928                } else {
929                    shared_serialize(serializer, field_value)?;
930                }
931            }
932            serializer.end_struct().map_err(SerializeError::Backend)?;
933        }
934        return Ok(());
935    }
936
937    if let Ok(enum_) = value.into_enum() {
938        let variant = enum_.active_variant().map_err(|_| {
939            SerializeError::Unsupported(Cow::Borrowed("opaque enum layout is unsupported"))
940        })?;
941
942        // Notify format of the variant being serialized (for xml::elements support)
943        serializer
944            .variant_metadata(variant)
945            .map_err(SerializeError::Backend)?;
946
947        if serializer.enum_variant_encoding() == EnumVariantEncoding::Index {
948            let variant_index = enum_.variant_index().map_err(|_| {
949                SerializeError::Unsupported(Cow::Borrowed("opaque enum layout is unsupported"))
950            })?;
951            serializer
952                .begin_enum_variant(variant_index, variant.name)
953                .map_err(SerializeError::Backend)?;
954
955            match variant.data.kind {
956                StructKind::Unit => return Ok(()),
957                StructKind::TupleStruct | StructKind::Tuple | StructKind::Struct => {
958                    // Index encoding is for binary formats - use binary serialize
959                    // to avoid skip predicates that would break positional deserialization.
960                    for (field_item, field_value) in enum_.fields_for_binary_serialize() {
961                        if let Some(proxy_def) = field_item
962                            .field
963                            .and_then(|f| f.effective_proxy(serializer.format_namespace()))
964                        {
965                            serialize_via_proxy(serializer, field_value, proxy_def)?;
966                        } else {
967                            shared_serialize(serializer, field_value)?;
968                        }
969                    }
970                    return Ok(());
971                }
972            }
973        }
974
975        let numeric = value.shape().is_numeric();
976        let untagged = value.shape().is_untagged();
977        let tag = value.shape().get_tag_attr();
978        let content = value.shape().get_content_attr();
979
980        if numeric {
981            return serialize_numeric_enum(serializer, variant);
982        }
983        if untagged {
984            return serialize_untagged_enum(serializer, enum_, variant);
985        }
986
987        match (tag, content) {
988            (Some(tag_key), None) => {
989                // Internally tagged.
990                serializer.begin_struct().map_err(SerializeError::Backend)?;
991                serializer
992                    .field_key(tag_key)
993                    .map_err(SerializeError::Backend)?;
994                serializer
995                    .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
996                    .map_err(SerializeError::Backend)?;
997
998                let field_mode = serializer.struct_field_mode();
999                match variant.data.kind {
1000                    StructKind::Unit => {}
1001                    StructKind::Struct => {
1002                        let mut fields: alloc::vec::Vec<_> =
1003                            if field_mode == StructFieldMode::Unnamed {
1004                                enum_.fields_for_binary_serialize().collect()
1005                            } else {
1006                                enum_.fields_for_serialize().collect()
1007                            };
1008                        sort_fields_if_needed(serializer, &mut fields);
1009                        for (field_item, field_value) in fields {
1010                            serializer
1011                                .field_metadata(&field_item)
1012                                .map_err(SerializeError::Backend)?;
1013                            if field_mode == StructFieldMode::Named {
1014                                serializer
1015                                    .field_key(field_item.effective_name())
1016                                    .map_err(SerializeError::Backend)?;
1017                            }
1018                            // Check for field-level proxy
1019                            if let Some(proxy_def) = field_item
1020                                .field
1021                                .and_then(|f| f.effective_proxy(serializer.format_namespace()))
1022                            {
1023                                serialize_via_proxy(serializer, field_value, proxy_def)?;
1024                            } else {
1025                                shared_serialize(serializer, field_value)?;
1026                            }
1027                        }
1028                    }
1029                    StructKind::TupleStruct | StructKind::Tuple => {
1030                        return Err(SerializeError::Unsupported(Cow::Borrowed(
1031                            "internally tagged tuple variants are not supported",
1032                        )));
1033                    }
1034                }
1035
1036                serializer.end_struct().map_err(SerializeError::Backend)?;
1037                return Ok(());
1038            }
1039            (Some(tag_key), Some(content_key)) => {
1040                // Adjacently tagged.
1041                let field_mode = serializer.struct_field_mode();
1042                serializer.begin_struct().map_err(SerializeError::Backend)?;
1043                serializer
1044                    .field_key(tag_key)
1045                    .map_err(SerializeError::Backend)?;
1046                serializer
1047                    .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
1048                    .map_err(SerializeError::Backend)?;
1049
1050                match variant.data.kind {
1051                    StructKind::Unit => {
1052                        // Unit variants with adjacent tagging omit the content field.
1053                    }
1054                    StructKind::Struct => {
1055                        serializer
1056                            .field_key(content_key)
1057                            .map_err(SerializeError::Backend)?;
1058                        serializer.begin_struct().map_err(SerializeError::Backend)?;
1059                        let mut fields: alloc::vec::Vec<_> =
1060                            if field_mode == StructFieldMode::Unnamed {
1061                                enum_.fields_for_binary_serialize().collect()
1062                            } else {
1063                                enum_.fields_for_serialize().collect()
1064                            };
1065                        sort_fields_if_needed(serializer, &mut fields);
1066                        for (field_item, field_value) in fields {
1067                            serializer
1068                                .field_metadata(&field_item)
1069                                .map_err(SerializeError::Backend)?;
1070                            if field_mode == StructFieldMode::Named {
1071                                serializer
1072                                    .field_key(field_item.effective_name())
1073                                    .map_err(SerializeError::Backend)?;
1074                            }
1075                            // Check for field-level proxy
1076                            if let Some(proxy_def) = field_item
1077                                .field
1078                                .and_then(|f| f.effective_proxy(serializer.format_namespace()))
1079                            {
1080                                serialize_via_proxy(serializer, field_value, proxy_def)?;
1081                            } else {
1082                                shared_serialize(serializer, field_value)?;
1083                            }
1084                        }
1085                        serializer.end_struct().map_err(SerializeError::Backend)?;
1086                    }
1087                    StructKind::TupleStruct | StructKind::Tuple => {
1088                        serializer
1089                            .field_key(content_key)
1090                            .map_err(SerializeError::Backend)?;
1091
1092                        let field_count = variant.data.fields.len();
1093                        if field_count == 1 {
1094                            let inner = enum_
1095                                .field(0)
1096                                .map_err(|_| {
1097                                    SerializeError::Internal(Cow::Borrowed(
1098                                        "variant field lookup failed",
1099                                    ))
1100                                })?
1101                                .ok_or(SerializeError::Internal(Cow::Borrowed(
1102                                    "variant reported 1 field but field(0) returned None",
1103                                )))?;
1104                            shared_serialize(serializer, inner)?;
1105                        } else {
1106                            serializer.begin_seq().map_err(SerializeError::Backend)?;
1107                            for idx in 0..field_count {
1108                                let inner = enum_
1109                                    .field(idx)
1110                                    .map_err(|_| {
1111                                        SerializeError::Internal(Cow::Borrowed(
1112                                            "variant field lookup failed",
1113                                        ))
1114                                    })?
1115                                    .ok_or(SerializeError::Internal(Cow::Borrowed(
1116                                        "variant field missing while iterating tuple fields",
1117                                    )))?;
1118                                shared_serialize(serializer, inner)?;
1119                            }
1120                            serializer.end_seq().map_err(SerializeError::Backend)?;
1121                        }
1122                    }
1123                }
1124
1125                serializer.end_struct().map_err(SerializeError::Backend)?;
1126                return Ok(());
1127            }
1128            (None, Some(_)) => {
1129                return Err(SerializeError::Unsupported(Cow::Borrowed(
1130                    "adjacent content key set without tag key",
1131                )));
1132            }
1133            (None, None) => {}
1134        }
1135
1136        // Externally tagged (default).
1137        // For #[facet(other)] variants with a #[facet(metadata = "tag")] field,
1138        // use the field's value as the tag name instead of the variant name.
1139        trace!(
1140            variant_name = variant.name,
1141            is_other = variant.is_other(),
1142            "serializing enum variant"
1143        );
1144        let field_mode = serializer.struct_field_mode();
1145        let tag_name: Cow<'_, str> = if variant.is_other() {
1146            // Look for a tag field in the variant's data.
1147            // For binary formats, use binary serialize to avoid skip predicates.
1148            let mut tag_value: Option<Cow<'_, str>> = None;
1149            let fields_iter: alloc::boxed::Box<
1150                dyn Iterator<Item = (facet_reflect::FieldItem, facet_reflect::Peek<'_, '_>)>,
1151            > = if field_mode == StructFieldMode::Unnamed {
1152                alloc::boxed::Box::new(enum_.fields_for_binary_serialize())
1153            } else {
1154                alloc::boxed::Box::new(enum_.fields_for_serialize())
1155            };
1156            for (field_item, field_value) in fields_iter {
1157                if let Some(field) = field_item.field {
1158                    trace!(
1159                        field_name = field.name,
1160                        is_variant_tag = field.is_variant_tag(),
1161                        "checking field for tag"
1162                    );
1163                    if field.is_variant_tag() {
1164                        // Extract the tag value - handle Option<String>
1165                        if let Ok(opt) = field_value.into_option()
1166                            && let Some(inner) = opt.value()
1167                            && let Some(s) = inner.as_str()
1168                        {
1169                            tag_value = Some(Cow::Borrowed(s));
1170                        }
1171                        break;
1172                    }
1173                }
1174            }
1175            tag_value.unwrap_or_else(|| Cow::Borrowed(variant.effective_name()))
1176        } else {
1177            Cow::Borrowed(variant.effective_name())
1178        };
1179
1180        // First, check if the format wants to handle this with tag syntax (e.g., Styx's @tag)
1181        let use_tag_syntax = serializer
1182            .write_variant_tag(&tag_name)
1183            .map_err(SerializeError::Backend)?;
1184
1185        if use_tag_syntax {
1186            // Format wrote the tag, now serialize the payload appropriately
1187            return match variant.data.kind {
1188                StructKind::Unit => {
1189                    // Nothing more to write for unit variants
1190                    Ok(())
1191                }
1192                StructKind::TupleStruct | StructKind::Tuple => {
1193                    let field_count = variant.data.fields.len();
1194                    if field_count == 1 {
1195                        // Newtype variant - serialize payload directly
1196                        let inner = enum_
1197                            .field(0)
1198                            .map_err(|_| {
1199                                SerializeError::Internal(Cow::Borrowed(
1200                                    "variant field lookup failed",
1201                                ))
1202                            })?
1203                            .ok_or(SerializeError::Internal(Cow::Borrowed(
1204                                "variant reported 1 field but field(0) returned None",
1205                            )))?;
1206                        shared_serialize(serializer, inner)?;
1207                    } else {
1208                        // Multi-field tuple - use sequence after tag
1209                        serializer
1210                            .begin_seq_after_tag()
1211                            .map_err(SerializeError::Backend)?;
1212                        for idx in 0..field_count {
1213                            let inner = enum_
1214                                .field(idx)
1215                                .map_err(|_| {
1216                                    SerializeError::Internal(Cow::Borrowed(
1217                                        "variant field lookup failed",
1218                                    ))
1219                                })?
1220                                .ok_or(SerializeError::Internal(Cow::Borrowed(
1221                                    "variant field missing while iterating tuple fields",
1222                                )))?;
1223                            shared_serialize(serializer, inner)?;
1224                        }
1225                        serializer.end_seq().map_err(SerializeError::Backend)?;
1226                    }
1227                    Ok(())
1228                }
1229                StructKind::Struct => {
1230                    // Struct variant - use struct after tag
1231                    // For #[facet(other)] variants, skip metadata fields (like tag) from payload
1232                    let is_other = variant.is_other();
1233                    let fields_iter: alloc::boxed::Box<
1234                        dyn Iterator<
1235                            Item = (facet_reflect::FieldItem, facet_reflect::Peek<'_, '_>),
1236                        >,
1237                    > = if field_mode == StructFieldMode::Unnamed {
1238                        alloc::boxed::Box::new(enum_.fields_for_binary_serialize())
1239                    } else {
1240                        alloc::boxed::Box::new(enum_.fields_for_serialize())
1241                    };
1242                    let mut fields: alloc::vec::Vec<_> = fields_iter
1243                        .filter(|(field_item, _)| {
1244                            if is_other {
1245                                // Skip metadata fields and tag fields for other variants
1246                                field_item
1247                                    .field
1248                                    .map(|f| f.metadata_kind().is_none() && !f.is_variant_tag())
1249                                    .unwrap_or(true)
1250                            } else {
1251                                true
1252                            }
1253                        })
1254                        .collect();
1255
1256                    // If no non-metadata fields remain, don't emit a struct at all
1257                    if fields.is_empty() {
1258                        return Ok(());
1259                    }
1260
1261                    serializer
1262                        .begin_struct_after_tag()
1263                        .map_err(SerializeError::Backend)?;
1264                    sort_fields_if_needed(serializer, &mut fields);
1265                    let field_mode = serializer.struct_field_mode();
1266                    for (field_item, field_value) in fields {
1267                        serializer
1268                            .field_metadata(&field_item)
1269                            .map_err(SerializeError::Backend)?;
1270                        if field_mode == StructFieldMode::Named {
1271                            serializer
1272                                .field_key(field_item.effective_name())
1273                                .map_err(SerializeError::Backend)?;
1274                        }
1275                        if let Some(proxy_def) = field_item
1276                            .field
1277                            .and_then(|f| f.effective_proxy(serializer.format_namespace()))
1278                        {
1279                            serialize_via_proxy(serializer, field_value, proxy_def)?;
1280                        } else {
1281                            shared_serialize(serializer, field_value)?;
1282                        }
1283                    }
1284                    serializer.end_struct().map_err(SerializeError::Backend)?;
1285                    Ok(())
1286                }
1287            };
1288        }
1289
1290        // Standard externally tagged representation: { "variant_name": payload }
1291        return match variant.data.kind {
1292            StructKind::Unit => {
1293                serializer
1294                    .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
1295                    .map_err(SerializeError::Backend)?;
1296                Ok(())
1297            }
1298            StructKind::TupleStruct | StructKind::Tuple => {
1299                serializer.begin_struct().map_err(SerializeError::Backend)?;
1300                serializer
1301                    .field_key(variant.effective_name())
1302                    .map_err(SerializeError::Backend)?;
1303
1304                let field_count = variant.data.fields.len();
1305                if field_count == 1 {
1306                    let inner = enum_
1307                        .field(0)
1308                        .map_err(|_| {
1309                            SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
1310                        })?
1311                        .ok_or(SerializeError::Internal(Cow::Borrowed(
1312                            "variant reported 1 field but field(0) returned None",
1313                        )))?;
1314                    shared_serialize(serializer, inner)?;
1315                } else {
1316                    serializer.begin_seq().map_err(SerializeError::Backend)?;
1317                    for idx in 0..field_count {
1318                        let inner = enum_
1319                            .field(idx)
1320                            .map_err(|_| {
1321                                SerializeError::Internal(Cow::Borrowed(
1322                                    "variant field lookup failed",
1323                                ))
1324                            })?
1325                            .ok_or(SerializeError::Internal(Cow::Borrowed(
1326                                "variant field missing while iterating tuple fields",
1327                            )))?;
1328                        shared_serialize(serializer, inner)?;
1329                    }
1330                    serializer.end_seq().map_err(SerializeError::Backend)?;
1331                }
1332
1333                serializer.end_struct().map_err(SerializeError::Backend)?;
1334                Ok(())
1335            }
1336            StructKind::Struct => {
1337                let field_mode = serializer.struct_field_mode();
1338                serializer.begin_struct().map_err(SerializeError::Backend)?;
1339                serializer
1340                    .field_key(variant.effective_name())
1341                    .map_err(SerializeError::Backend)?;
1342
1343                serializer.begin_struct().map_err(SerializeError::Backend)?;
1344                let mut fields: alloc::vec::Vec<_> = if field_mode == StructFieldMode::Unnamed {
1345                    enum_.fields_for_binary_serialize().collect()
1346                } else {
1347                    enum_.fields_for_serialize().collect()
1348                };
1349                sort_fields_if_needed(serializer, &mut fields);
1350                for (field_item, field_value) in fields {
1351                    serializer
1352                        .field_metadata(&field_item)
1353                        .map_err(SerializeError::Backend)?;
1354                    if field_mode == StructFieldMode::Named {
1355                        serializer
1356                            .field_key(field_item.effective_name())
1357                            .map_err(SerializeError::Backend)?;
1358                    }
1359                    // Check for field-level proxy
1360                    if let Some(proxy_def) = field_item
1361                        .field
1362                        .and_then(|f| f.effective_proxy(serializer.format_namespace()))
1363                    {
1364                        serialize_via_proxy(serializer, field_value, proxy_def)?;
1365                    } else {
1366                        shared_serialize(serializer, field_value)?;
1367                    }
1368                }
1369                serializer.end_struct().map_err(SerializeError::Backend)?;
1370
1371                serializer.end_struct().map_err(SerializeError::Backend)?;
1372                Ok(())
1373            }
1374        };
1375    }
1376
1377    Err(SerializeError::Unsupported(Cow::Borrowed(
1378        "unsupported value kind for serialization",
1379    )))
1380}
1381
1382fn serialize_dynamic_value<'mem, 'facet, S>(
1383    serializer: &mut S,
1384    dynamic: facet_reflect::PeekDynamicValue<'mem, 'facet>,
1385) -> Result<(), SerializeError<S::Error>>
1386where
1387    S: FormatSerializer,
1388{
1389    let tagged = serializer.dynamic_value_encoding() == DynamicValueEncoding::Tagged;
1390
1391    match dynamic.kind() {
1392        DynValueKind::Null => {
1393            if tagged {
1394                serializer
1395                    .dynamic_value_tag(DynamicValueTag::Null)
1396                    .map_err(SerializeError::Backend)?;
1397            }
1398            serializer
1399                .scalar(ScalarValue::Null)
1400                .map_err(SerializeError::Backend)
1401        }
1402        DynValueKind::Bool => {
1403            let value = dynamic.as_bool().ok_or_else(|| {
1404                SerializeError::Internal(Cow::Borrowed("dynamic bool missing value"))
1405            })?;
1406            if tagged {
1407                serializer
1408                    .dynamic_value_tag(DynamicValueTag::Bool)
1409                    .map_err(SerializeError::Backend)?;
1410            }
1411            serializer
1412                .scalar(ScalarValue::Bool(value))
1413                .map_err(SerializeError::Backend)
1414        }
1415        DynValueKind::Number => {
1416            if let Some(n) = dynamic.as_i64() {
1417                if tagged {
1418                    serializer
1419                        .dynamic_value_tag(DynamicValueTag::I64)
1420                        .map_err(SerializeError::Backend)?;
1421                }
1422                serializer
1423                    .scalar(ScalarValue::I64(n))
1424                    .map_err(SerializeError::Backend)
1425            } else if let Some(n) = dynamic.as_u64() {
1426                if tagged {
1427                    serializer
1428                        .dynamic_value_tag(DynamicValueTag::U64)
1429                        .map_err(SerializeError::Backend)?;
1430                }
1431                serializer
1432                    .scalar(ScalarValue::U64(n))
1433                    .map_err(SerializeError::Backend)
1434            } else if let Some(n) = dynamic.as_f64() {
1435                if tagged {
1436                    serializer
1437                        .dynamic_value_tag(DynamicValueTag::F64)
1438                        .map_err(SerializeError::Backend)?;
1439                }
1440                serializer
1441                    .scalar(ScalarValue::F64(n))
1442                    .map_err(SerializeError::Backend)
1443            } else {
1444                Err(SerializeError::Unsupported(Cow::Borrowed(
1445                    "dynamic number not representable",
1446                )))
1447            }
1448        }
1449        DynValueKind::String => {
1450            let value = dynamic.as_str().ok_or_else(|| {
1451                SerializeError::Internal(Cow::Borrowed("dynamic string missing value"))
1452            })?;
1453            if tagged {
1454                serializer
1455                    .dynamic_value_tag(DynamicValueTag::String)
1456                    .map_err(SerializeError::Backend)?;
1457            }
1458            serializer
1459                .scalar(ScalarValue::Str(Cow::Borrowed(value)))
1460                .map_err(SerializeError::Backend)
1461        }
1462        DynValueKind::Bytes => {
1463            let value = dynamic.as_bytes().ok_or_else(|| {
1464                SerializeError::Internal(Cow::Borrowed("dynamic bytes missing value"))
1465            })?;
1466            if tagged {
1467                serializer
1468                    .dynamic_value_tag(DynamicValueTag::Bytes)
1469                    .map_err(SerializeError::Backend)?;
1470            }
1471            serializer
1472                .scalar(ScalarValue::Bytes(Cow::Borrowed(value)))
1473                .map_err(SerializeError::Backend)
1474        }
1475        DynValueKind::Array => {
1476            let len = dynamic.array_len().ok_or_else(|| {
1477                SerializeError::Internal(Cow::Borrowed("dynamic array missing length"))
1478            })?;
1479            if tagged {
1480                serializer
1481                    .dynamic_value_tag(DynamicValueTag::Array)
1482                    .map_err(SerializeError::Backend)?;
1483            }
1484            serializer
1485                .begin_seq_with_len(len)
1486                .map_err(SerializeError::Backend)?;
1487            if let Some(iter) = dynamic.array_iter() {
1488                for item in iter {
1489                    shared_serialize(serializer, item)?;
1490                }
1491            }
1492            serializer.end_seq().map_err(SerializeError::Backend)
1493        }
1494        DynValueKind::Object => {
1495            let len = dynamic.object_len().ok_or_else(|| {
1496                SerializeError::Internal(Cow::Borrowed("dynamic object missing length"))
1497            })?;
1498            if tagged {
1499                serializer
1500                    .dynamic_value_tag(DynamicValueTag::Object)
1501                    .map_err(SerializeError::Backend)?;
1502            }
1503            match serializer.map_encoding() {
1504                MapEncoding::Pairs => {
1505                    serializer
1506                        .begin_map_with_len(len)
1507                        .map_err(SerializeError::Backend)?;
1508                    if let Some(iter) = dynamic.object_iter() {
1509                        for (key, value) in iter {
1510                            serializer
1511                                .scalar(ScalarValue::Str(Cow::Borrowed(key)))
1512                                .map_err(SerializeError::Backend)?;
1513                            shared_serialize(serializer, value)?;
1514                        }
1515                    }
1516                    serializer.end_map().map_err(SerializeError::Backend)
1517                }
1518                MapEncoding::Struct => {
1519                    serializer.begin_struct().map_err(SerializeError::Backend)?;
1520                    if let Some(iter) = dynamic.object_iter() {
1521                        for (key, value) in iter {
1522                            serializer.field_key(key).map_err(SerializeError::Backend)?;
1523                            shared_serialize(serializer, value)?;
1524                        }
1525                    }
1526                    serializer.end_struct().map_err(SerializeError::Backend)
1527                }
1528            }
1529        }
1530        DynValueKind::DateTime => {
1531            let dt = dynamic.as_datetime().ok_or_else(|| {
1532                SerializeError::Internal(Cow::Borrowed("dynamic datetime missing value"))
1533            })?;
1534            if tagged {
1535                serializer
1536                    .dynamic_value_tag(DynamicValueTag::DateTime)
1537                    .map_err(SerializeError::Backend)?;
1538            }
1539            let s = format_dyn_datetime(dt);
1540            serializer
1541                .scalar(ScalarValue::Str(Cow::Owned(s)))
1542                .map_err(SerializeError::Backend)
1543        }
1544        DynValueKind::QName | DynValueKind::Uuid => Err(SerializeError::Unsupported(
1545            Cow::Borrowed("dynamic QName/Uuid serialization is not supported"),
1546        )),
1547    }
1548}
1549
1550fn format_dyn_datetime(
1551    (year, month, day, hour, minute, second, nanos, kind): (
1552        i32,
1553        u8,
1554        u8,
1555        u8,
1556        u8,
1557        u8,
1558        u32,
1559        DynDateTimeKind,
1560    ),
1561) -> String {
1562    let mut out = String::new();
1563    match kind {
1564        DynDateTimeKind::Offset { offset_minutes } => {
1565            let _ = write!(
1566                out,
1567                "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
1568                year, month, day, hour, minute, second
1569            );
1570            if nanos > 0 {
1571                let _ = write!(out, ".{:09}", nanos);
1572            }
1573            if offset_minutes == 0 {
1574                out.push('Z');
1575            } else {
1576                let sign = if offset_minutes >= 0 { '+' } else { '-' };
1577                let abs = offset_minutes.unsigned_abs();
1578                let _ = write!(out, "{}{:02}:{:02}", sign, abs / 60, abs % 60);
1579            }
1580        }
1581        DynDateTimeKind::LocalDateTime => {
1582            let _ = write!(
1583                out,
1584                "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
1585                year, month, day, hour, minute, second
1586            );
1587            if nanos > 0 {
1588                let _ = write!(out, ".{:09}", nanos);
1589            }
1590        }
1591        DynDateTimeKind::LocalDate => {
1592            let _ = write!(out, "{:04}-{:02}-{:02}", year, month, day);
1593        }
1594        DynDateTimeKind::LocalTime => {
1595            let _ = write!(out, "{:02}:{:02}:{:02}", hour, minute, second);
1596            if nanos > 0 {
1597                let _ = write!(out, ".{:09}", nanos);
1598            }
1599        }
1600    }
1601    out
1602}
1603
1604fn serialize_numeric_enum<S>(
1605    serializer: &mut S,
1606    variant: &'static facet_core::Variant,
1607) -> Result<(), SerializeError<S::Error>>
1608where
1609    S: FormatSerializer,
1610{
1611    let discriminant = variant
1612        .discriminant
1613        .ok_or(SerializeError::Unsupported(Cow::Borrowed(
1614            "Enum without a discriminant",
1615        )))?;
1616    serializer
1617        .scalar(ScalarValue::I64(discriminant))
1618        .map_err(SerializeError::Backend)
1619}
1620
1621fn serialize_untagged_enum<'mem, 'facet, S>(
1622    serializer: &mut S,
1623    enum_: facet_reflect::PeekEnum<'mem, 'facet>,
1624    variant: &'static facet_core::Variant,
1625) -> Result<(), SerializeError<S::Error>>
1626where
1627    S: FormatSerializer,
1628{
1629    match variant.data.kind {
1630        StructKind::Unit => serializer
1631            .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
1632            .map_err(SerializeError::Backend),
1633        StructKind::TupleStruct | StructKind::Tuple => {
1634            let field_count = variant.data.fields.len();
1635            if field_count == 1 {
1636                let inner = enum_
1637                    .field(0)
1638                    .map_err(|_| {
1639                        SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
1640                    })?
1641                    .ok_or(SerializeError::Internal(Cow::Borrowed(
1642                        "variant reported 1 field but field(0) returned None",
1643                    )))?;
1644                shared_serialize(serializer, inner)
1645            } else {
1646                serializer.begin_seq().map_err(SerializeError::Backend)?;
1647                for idx in 0..field_count {
1648                    let inner = enum_
1649                        .field(idx)
1650                        .map_err(|_| {
1651                            SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
1652                        })?
1653                        .ok_or(SerializeError::Internal(Cow::Borrowed(
1654                            "variant field missing while iterating tuple fields",
1655                        )))?;
1656                    shared_serialize(serializer, inner)?;
1657                }
1658                serializer.end_seq().map_err(SerializeError::Backend)?;
1659                Ok(())
1660            }
1661        }
1662        StructKind::Struct => {
1663            let field_mode = serializer.struct_field_mode();
1664            serializer.begin_struct().map_err(SerializeError::Backend)?;
1665            let mut fields: alloc::vec::Vec<_> = if field_mode == StructFieldMode::Unnamed {
1666                enum_.fields_for_binary_serialize().collect()
1667            } else {
1668                enum_.fields_for_serialize().collect()
1669            };
1670            sort_fields_if_needed(serializer, &mut fields);
1671            for (field_item, field_value) in fields {
1672                serializer
1673                    .field_metadata(&field_item)
1674                    .map_err(SerializeError::Backend)?;
1675                if field_mode == StructFieldMode::Named {
1676                    serializer
1677                        .field_key(field_item.effective_name())
1678                        .map_err(SerializeError::Backend)?;
1679                }
1680                // Check for field-level proxy
1681                if let Some(proxy_def) = field_item
1682                    .field
1683                    .and_then(|f| f.effective_proxy(serializer.format_namespace()))
1684                {
1685                    serialize_via_proxy(serializer, field_value, proxy_def)?;
1686                } else {
1687                    shared_serialize(serializer, field_value)?;
1688                }
1689            }
1690            serializer.end_struct().map_err(SerializeError::Backend)?;
1691            Ok(())
1692        }
1693    }
1694}
1695
1696/// Dereference a pointer/reference (Box, Arc, etc.) to get the underlying value
1697fn deref_if_pointer<'mem, 'facet>(peek: Peek<'mem, 'facet>) -> Peek<'mem, 'facet> {
1698    if let Ok(ptr) = peek.into_pointer()
1699        && let Some(target) = ptr.borrow_inner()
1700    {
1701        return deref_if_pointer(target);
1702    }
1703    peek
1704}
1705
1706/// Serialize a value through its proxy type.
1707///
1708/// # Safety note
1709/// This function requires unsafe code to:
1710/// - Allocate memory for the proxy type
1711/// - Call the conversion function from target to proxy
1712/// - Drop the proxy value after serialization
1713#[allow(unsafe_code)]
1714fn serialize_via_proxy<'mem, 'facet, S>(
1715    serializer: &mut S,
1716    value: Peek<'mem, 'facet>,
1717    proxy_def: &'static facet_core::ProxyDef,
1718) -> Result<(), SerializeError<S::Error>>
1719where
1720    S: FormatSerializer,
1721{
1722    use facet_core::PtrUninit;
1723
1724    let proxy_shape = proxy_def.shape;
1725    let proxy_layout = proxy_shape.layout.sized_layout().map_err(|_| {
1726        SerializeError::Unsupported(Cow::Borrowed("proxy type must be sized for serialization"))
1727    })?;
1728
1729    // Allocate memory for the proxy value
1730    let proxy_mem = unsafe { alloc::alloc::alloc(proxy_layout) };
1731    if proxy_mem.is_null() {
1732        return Err(SerializeError::Internal(Cow::Borrowed(
1733            "failed to allocate proxy memory",
1734        )));
1735    }
1736
1737    // Convert target → proxy
1738    let proxy_uninit = PtrUninit::new(proxy_mem);
1739    let convert_result = unsafe { (proxy_def.convert_out)(value.data(), proxy_uninit) };
1740
1741    let proxy_ptr = match convert_result {
1742        Ok(ptr) => ptr,
1743        Err(msg) => {
1744            unsafe { alloc::alloc::dealloc(proxy_mem, proxy_layout) };
1745            return Err(SerializeError::Unsupported(Cow::Owned(msg)));
1746        }
1747    };
1748
1749    // Create a Peek to the proxy value and serialize it
1750    let proxy_peek = unsafe { Peek::unchecked_new(proxy_ptr.as_const(), proxy_shape) };
1751    let result = shared_serialize(serializer, proxy_peek);
1752
1753    // Clean up: drop the proxy value and deallocate
1754    unsafe {
1755        let _ = proxy_shape.call_drop_in_place(proxy_ptr);
1756        alloc::alloc::dealloc(proxy_mem, proxy_layout);
1757    }
1758
1759    result
1760}
1761
1762// ─────────────────────────────────────────────────────────────────────────────
1763// Shape-guided serialization of dynamic values
1764// ─────────────────────────────────────────────────────────────────────────────
1765
1766/// Serialize a dynamic value (like `facet_value::Value`) according to a target shape.
1767///
1768/// This is the inverse of `FormatDeserializer::deserialize_with_shape`. It allows serializing
1769/// a `Value` as if it were a typed value matching the shape, without the dynamic value's
1770/// type discriminants.
1771///
1772/// This is useful for non-self-describing formats like postcard where you want to:
1773/// 1. Parse JSON into a `Value`
1774/// 2. Serialize it to postcard bytes matching a typed schema
1775///
1776/// # Arguments
1777///
1778/// * `serializer` - The format serializer to use
1779/// * `value` - A `Peek` into a dynamic value type (like `facet_value::Value`)
1780/// * `target_shape` - The shape describing the expected wire format
1781///
1782/// # Errors
1783///
1784/// Returns an error if:
1785/// - The value is not a dynamic value type
1786/// - The value's structure doesn't match the target shape
1787pub fn serialize_value_with_shape<S>(
1788    serializer: &mut S,
1789    value: Peek<'_, '_>,
1790    target_shape: &'static Shape,
1791) -> Result<(), SerializeError<S::Error>>
1792where
1793    S: FormatSerializer,
1794{
1795    let dynamic = value.into_dynamic_value().map_err(|_| {
1796        SerializeError::Unsupported(Cow::Borrowed(
1797            "serialize_value_with_shape requires a DynamicValue type",
1798        ))
1799    })?;
1800
1801    serialize_dynamic_with_shape(serializer, dynamic, target_shape, value.shape())
1802}
1803
1804fn serialize_dynamic_with_shape<S>(
1805    serializer: &mut S,
1806    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1807    target_shape: &'static Shape,
1808    value_shape: &'static Shape,
1809) -> Result<(), SerializeError<S::Error>>
1810where
1811    S: FormatSerializer,
1812{
1813    use facet_core::{ListDef, OptionDef, ScalarType as CoreScalarType, Type, UserType};
1814
1815    // Handle smart pointers - unwrap to the inner shape
1816    if let Def::Pointer(ptr_def) = target_shape.def
1817        && let Some(pointee) = ptr_def.pointee
1818    {
1819        return serialize_dynamic_with_shape(serializer, dynamic, pointee, value_shape);
1820    }
1821
1822    // Handle transparent wrappers via .inner
1823    if let Some(inner_shape) = target_shape.inner {
1824        // Skip collection types that have .inner for variance but aren't transparent wrappers
1825        if !matches!(
1826            target_shape.def,
1827            Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
1828        ) {
1829            return serialize_dynamic_with_shape(serializer, dynamic, inner_shape, value_shape);
1830        }
1831    }
1832
1833    // Handle Option<T>
1834    if let Def::Option(OptionDef { t: inner_shape, .. }) = target_shape.def {
1835        return serialize_option_from_dynamic(serializer, dynamic, inner_shape, value_shape);
1836    }
1837
1838    // Handle List/Vec
1839    if let Def::List(ListDef { t: item_shape, .. }) = target_shape.def {
1840        return serialize_list_from_dynamic(serializer, dynamic, item_shape, value_shape);
1841    }
1842
1843    // Handle Array [T; N]
1844    if let Def::Array(array_def) = target_shape.def {
1845        return serialize_array_from_dynamic(serializer, dynamic, array_def.t, value_shape);
1846    }
1847
1848    // Handle Map
1849    if let Def::Map(map_def) = target_shape.def {
1850        return serialize_map_from_dynamic(serializer, dynamic, map_def.k, map_def.v, value_shape);
1851    }
1852
1853    // Handle scalars
1854    if let Some(scalar_type) = CoreScalarType::try_from_shape(target_shape) {
1855        return serialize_scalar_from_dynamic(serializer, dynamic, scalar_type);
1856    }
1857
1858    // Handle structs and enums by Type
1859    match target_shape.ty {
1860        Type::User(UserType::Struct(struct_def)) => {
1861            serialize_struct_from_dynamic(serializer, dynamic, struct_def, value_shape)
1862        }
1863        Type::User(UserType::Enum(enum_def)) => {
1864            serialize_enum_from_dynamic(serializer, dynamic, enum_def, target_shape, value_shape)
1865        }
1866        _ => Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
1867            "unsupported target shape for serialize_value_with_shape: {}",
1868            target_shape
1869        )))),
1870    }
1871}
1872
1873fn serialize_option_from_dynamic<S>(
1874    serializer: &mut S,
1875    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1876    inner_shape: &'static Shape,
1877    value_shape: &'static Shape,
1878) -> Result<(), SerializeError<S::Error>>
1879where
1880    S: FormatSerializer,
1881{
1882    if dynamic.kind() == DynValueKind::Null {
1883        serializer.serialize_none().map_err(SerializeError::Backend)
1884    } else {
1885        serializer
1886            .begin_option_some()
1887            .map_err(SerializeError::Backend)?;
1888        serialize_dynamic_with_shape(serializer, dynamic, inner_shape, value_shape)
1889    }
1890}
1891
1892fn serialize_list_from_dynamic<S>(
1893    serializer: &mut S,
1894    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1895    item_shape: &'static Shape,
1896    value_shape: &'static Shape,
1897) -> Result<(), SerializeError<S::Error>>
1898where
1899    S: FormatSerializer,
1900{
1901    let len = dynamic.array_len().ok_or_else(|| {
1902        SerializeError::Unsupported(Cow::Borrowed(
1903            "expected array value for list/vec target shape",
1904        ))
1905    })?;
1906
1907    serializer
1908        .begin_seq_with_len(len)
1909        .map_err(SerializeError::Backend)?;
1910
1911    if let Some(iter) = dynamic.array_iter() {
1912        for elem in iter {
1913            let elem_dyn = elem.into_dynamic_value().map_err(|_| {
1914                SerializeError::Internal(Cow::Borrowed("array element is not a dynamic value"))
1915            })?;
1916            serialize_dynamic_with_shape(serializer, elem_dyn, item_shape, value_shape)?;
1917        }
1918    }
1919
1920    serializer.end_seq().map_err(SerializeError::Backend)
1921}
1922
1923fn serialize_array_from_dynamic<S>(
1924    serializer: &mut S,
1925    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1926    item_shape: &'static Shape,
1927    value_shape: &'static Shape,
1928) -> Result<(), SerializeError<S::Error>>
1929where
1930    S: FormatSerializer,
1931{
1932    // Arrays don't have length prefix in postcard
1933    serializer.begin_seq().map_err(SerializeError::Backend)?;
1934
1935    if let Some(iter) = dynamic.array_iter() {
1936        for elem in iter {
1937            let elem_dyn = elem.into_dynamic_value().map_err(|_| {
1938                SerializeError::Internal(Cow::Borrowed("array element is not a dynamic value"))
1939            })?;
1940            serialize_dynamic_with_shape(serializer, elem_dyn, item_shape, value_shape)?;
1941        }
1942    }
1943
1944    serializer.end_seq().map_err(SerializeError::Backend)
1945}
1946
1947fn serialize_map_from_dynamic<S>(
1948    serializer: &mut S,
1949    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1950    key_shape: &'static Shape,
1951    value_shape_inner: &'static Shape,
1952    value_shape: &'static Shape,
1953) -> Result<(), SerializeError<S::Error>>
1954where
1955    S: FormatSerializer,
1956{
1957    let len = dynamic.object_len().ok_or_else(|| {
1958        SerializeError::Unsupported(Cow::Borrowed("expected object value for map target shape"))
1959    })?;
1960
1961    match serializer.map_encoding() {
1962        MapEncoding::Pairs => {
1963            serializer
1964                .begin_map_with_len(len)
1965                .map_err(SerializeError::Backend)?;
1966
1967            if let Some(iter) = dynamic.object_iter() {
1968                for (key, val) in iter {
1969                    // Serialize key according to key_shape
1970                    serialize_string_as_scalar(serializer, key, key_shape)?;
1971                    // Serialize value
1972                    let val_dyn = val.into_dynamic_value().map_err(|_| {
1973                        SerializeError::Internal(Cow::Borrowed(
1974                            "object value is not a dynamic value",
1975                        ))
1976                    })?;
1977                    serialize_dynamic_with_shape(
1978                        serializer,
1979                        val_dyn,
1980                        value_shape_inner,
1981                        value_shape,
1982                    )?;
1983                }
1984            }
1985
1986            serializer.end_map().map_err(SerializeError::Backend)
1987        }
1988        MapEncoding::Struct => {
1989            serializer.begin_struct().map_err(SerializeError::Backend)?;
1990
1991            if let Some(iter) = dynamic.object_iter() {
1992                for (key, val) in iter {
1993                    serializer.field_key(key).map_err(SerializeError::Backend)?;
1994                    let val_dyn = val.into_dynamic_value().map_err(|_| {
1995                        SerializeError::Internal(Cow::Borrowed(
1996                            "object value is not a dynamic value",
1997                        ))
1998                    })?;
1999                    serialize_dynamic_with_shape(
2000                        serializer,
2001                        val_dyn,
2002                        value_shape_inner,
2003                        value_shape,
2004                    )?;
2005                }
2006            }
2007
2008            serializer.end_struct().map_err(SerializeError::Backend)
2009        }
2010    }
2011}
2012
2013fn serialize_string_as_scalar<S>(
2014    serializer: &mut S,
2015    s: &str,
2016    _key_shape: &'static Shape,
2017) -> Result<(), SerializeError<S::Error>>
2018where
2019    S: FormatSerializer,
2020{
2021    // For now, serialize string keys directly
2022    // TODO: Handle non-string key types if needed
2023    serializer
2024        .scalar(ScalarValue::Str(Cow::Borrowed(s)))
2025        .map_err(SerializeError::Backend)
2026}
2027
2028fn serialize_scalar_from_dynamic<S>(
2029    serializer: &mut S,
2030    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2031    scalar_type: facet_core::ScalarType,
2032) -> Result<(), SerializeError<S::Error>>
2033where
2034    S: FormatSerializer,
2035{
2036    use facet_core::ScalarType as ST;
2037
2038    match scalar_type {
2039        ST::Unit => serializer
2040            .scalar(ScalarValue::Null)
2041            .map_err(SerializeError::Backend),
2042        ST::Bool => {
2043            let v = dynamic
2044                .as_bool()
2045                .ok_or_else(|| SerializeError::Unsupported(Cow::Borrowed("expected bool value")))?;
2046            serializer
2047                .scalar(ScalarValue::Bool(v))
2048                .map_err(SerializeError::Backend)
2049        }
2050        ST::Char => {
2051            let s = dynamic.as_str().ok_or_else(|| {
2052                SerializeError::Unsupported(Cow::Borrowed("expected string value for char"))
2053            })?;
2054            let c = s.chars().next().ok_or_else(|| {
2055                SerializeError::Unsupported(Cow::Borrowed("expected non-empty string for char"))
2056            })?;
2057            serializer
2058                .scalar(ScalarValue::Char(c))
2059                .map_err(SerializeError::Backend)
2060        }
2061        ST::Str | ST::String | ST::CowStr => {
2062            let s = dynamic.as_str().ok_or_else(|| {
2063                SerializeError::Unsupported(Cow::Borrowed("expected string value"))
2064            })?;
2065            serializer
2066                .scalar(ScalarValue::Str(Cow::Borrowed(s)))
2067                .map_err(SerializeError::Backend)
2068        }
2069        ST::U8 | ST::U16 | ST::U32 | ST::U64 | ST::USize => {
2070            let n = dynamic.as_u64().ok_or_else(|| {
2071                SerializeError::Unsupported(Cow::Borrowed("expected unsigned integer value"))
2072            })?;
2073            serializer
2074                .scalar(ScalarValue::U64(n))
2075                .map_err(SerializeError::Backend)
2076        }
2077        ST::U128 => {
2078            let n = dynamic.as_u64().ok_or_else(|| {
2079                SerializeError::Unsupported(Cow::Borrowed("expected unsigned integer value"))
2080            })?;
2081            serializer
2082                .scalar(ScalarValue::U128(n as u128))
2083                .map_err(SerializeError::Backend)
2084        }
2085        ST::I8 | ST::I16 | ST::I32 | ST::I64 | ST::ISize => {
2086            let n = dynamic.as_i64().ok_or_else(|| {
2087                SerializeError::Unsupported(Cow::Borrowed("expected signed integer value"))
2088            })?;
2089            serializer
2090                .scalar(ScalarValue::I64(n))
2091                .map_err(SerializeError::Backend)
2092        }
2093        ST::I128 => {
2094            let n = dynamic.as_i64().ok_or_else(|| {
2095                SerializeError::Unsupported(Cow::Borrowed("expected signed integer value"))
2096            })?;
2097            serializer
2098                .scalar(ScalarValue::I128(n as i128))
2099                .map_err(SerializeError::Backend)
2100        }
2101        ST::F32 | ST::F64 => {
2102            let n = dynamic.as_f64().ok_or_else(|| {
2103                SerializeError::Unsupported(Cow::Borrowed("expected float value"))
2104            })?;
2105            serializer
2106                .scalar(ScalarValue::F64(n))
2107                .map_err(SerializeError::Backend)
2108        }
2109        _ => Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2110            "unsupported scalar type: {:?}",
2111            scalar_type
2112        )))),
2113    }
2114}
2115
2116fn serialize_struct_from_dynamic<S>(
2117    serializer: &mut S,
2118    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2119    struct_def: facet_core::StructType,
2120    value_shape: &'static Shape,
2121) -> Result<(), SerializeError<S::Error>>
2122where
2123    S: FormatSerializer,
2124{
2125    let is_tuple = matches!(struct_def.kind, StructKind::Tuple | StructKind::TupleStruct);
2126
2127    if is_tuple {
2128        // For tuples, expect an array value
2129        serializer.begin_seq().map_err(SerializeError::Backend)?;
2130
2131        let iter = dynamic.array_iter().ok_or_else(|| {
2132            SerializeError::Unsupported(Cow::Borrowed("expected array value for tuple"))
2133        })?;
2134
2135        for (field, elem) in struct_def.fields.iter().zip(iter) {
2136            let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2137                SerializeError::Internal(Cow::Borrowed("tuple element is not a dynamic value"))
2138            })?;
2139            serialize_dynamic_with_shape(serializer, elem_dyn, field.shape(), value_shape)?;
2140        }
2141
2142        serializer.end_seq().map_err(SerializeError::Backend)
2143    } else {
2144        // For named structs, expect an object value
2145        let field_mode = serializer.struct_field_mode();
2146
2147        serializer.begin_struct().map_err(SerializeError::Backend)?;
2148
2149        for field in struct_def.fields {
2150            // Skip metadata fields
2151            if field.is_metadata() {
2152                continue;
2153            }
2154
2155            let field_name = field.name;
2156            let field_value = dynamic.object_get(field_name).ok_or_else(|| {
2157                SerializeError::Unsupported(Cow::Owned(alloc::format!(
2158                    "missing field '{}' in object",
2159                    field_name
2160                )))
2161            })?;
2162
2163            if field_mode == StructFieldMode::Named {
2164                serializer
2165                    .field_key(field_name)
2166                    .map_err(SerializeError::Backend)?;
2167            }
2168
2169            let field_dyn = field_value.into_dynamic_value().map_err(|_| {
2170                SerializeError::Internal(Cow::Borrowed("field value is not a dynamic value"))
2171            })?;
2172            serialize_dynamic_with_shape(serializer, field_dyn, field.shape(), value_shape)?;
2173        }
2174
2175        serializer.end_struct().map_err(SerializeError::Backend)
2176    }
2177}
2178
2179fn serialize_enum_from_dynamic<S>(
2180    serializer: &mut S,
2181    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2182    enum_def: facet_core::EnumType,
2183    target_shape: &'static Shape,
2184    value_shape: &'static Shape,
2185) -> Result<(), SerializeError<S::Error>>
2186where
2187    S: FormatSerializer,
2188{
2189    // For index-based encoding (postcard), we need to:
2190    // 1. Determine the variant from the Value
2191    // 2. Emit the variant index
2192    // 3. Serialize the variant's payload
2193
2194    let use_index = serializer.enum_variant_encoding() == EnumVariantEncoding::Index;
2195
2196    match dynamic.kind() {
2197        // Unit variant represented as a string
2198        DynValueKind::String => {
2199            let variant_name = dynamic.as_str().ok_or_else(|| {
2200                SerializeError::Internal(Cow::Borrowed("expected string for unit variant"))
2201            })?;
2202
2203            let (variant_index, variant) = enum_def
2204                .variants
2205                .iter()
2206                .enumerate()
2207                .find(|(_, v)| v.effective_name() == variant_name)
2208                .ok_or_else(|| {
2209                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2210                        "unknown variant '{}'",
2211                        variant_name
2212                    )))
2213                })?;
2214
2215            if use_index {
2216                serializer
2217                    .begin_enum_variant(variant_index, variant.effective_name())
2218                    .map_err(SerializeError::Backend)?;
2219                // Unit variant has no payload
2220                Ok(())
2221            } else {
2222                serializer
2223                    .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
2224                    .map_err(SerializeError::Backend)
2225            }
2226        }
2227
2228        // Variant with payload represented as object { "VariantName": payload }
2229        DynValueKind::Object => {
2230            // For externally tagged enums, the object has a single key = variant name
2231            let obj_len = dynamic.object_len().unwrap_or(0);
2232            if obj_len != 1 {
2233                return Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2234                    "expected single-key object for enum variant, got {} keys",
2235                    obj_len
2236                ))));
2237            }
2238
2239            let (variant_name, payload) = dynamic.object_get_entry(0).ok_or_else(|| {
2240                SerializeError::Internal(Cow::Borrowed("expected object entry for enum variant"))
2241            })?;
2242
2243            let (variant_index, variant) = enum_def
2244                .variants
2245                .iter()
2246                .enumerate()
2247                .find(|(_, v)| v.effective_name() == variant_name)
2248                .ok_or_else(|| {
2249                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2250                        "unknown variant '{}'",
2251                        variant_name
2252                    )))
2253                })?;
2254
2255            let payload_dyn = payload.into_dynamic_value().map_err(|_| {
2256                SerializeError::Internal(Cow::Borrowed("variant payload is not a dynamic value"))
2257            })?;
2258
2259            if use_index {
2260                serializer
2261                    .begin_enum_variant(variant_index, variant.effective_name())
2262                    .map_err(SerializeError::Backend)?;
2263
2264                // Serialize payload based on variant kind
2265                match variant.data.kind {
2266                    StructKind::Unit => {
2267                        // No payload to serialize
2268                    }
2269                    StructKind::TupleStruct | StructKind::Tuple => {
2270                        if variant.data.fields.len() == 1 {
2271                            // Newtype variant - serialize the single field directly
2272                            serialize_dynamic_with_shape(
2273                                serializer,
2274                                payload_dyn,
2275                                variant.data.fields[0].shape(),
2276                                value_shape,
2277                            )?;
2278                        } else {
2279                            // Multi-field tuple variant - expect array
2280                            let iter = payload_dyn.array_iter().ok_or_else(|| {
2281                                SerializeError::Unsupported(Cow::Borrowed(
2282                                    "expected array for tuple variant payload",
2283                                ))
2284                            })?;
2285
2286                            for (field, elem) in variant.data.fields.iter().zip(iter) {
2287                                let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2288                                    SerializeError::Internal(Cow::Borrowed(
2289                                        "tuple element is not a dynamic value",
2290                                    ))
2291                                })?;
2292                                serialize_dynamic_with_shape(
2293                                    serializer,
2294                                    elem_dyn,
2295                                    field.shape(),
2296                                    value_shape,
2297                                )?;
2298                            }
2299                        }
2300                    }
2301                    StructKind::Struct => {
2302                        // Struct variant - expect object
2303                        for field in variant.data.fields {
2304                            let field_value =
2305                                payload_dyn.object_get(field.name).ok_or_else(|| {
2306                                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2307                                        "missing field '{}' in struct variant",
2308                                        field.name
2309                                    )))
2310                                })?;
2311                            let field_dyn = field_value.into_dynamic_value().map_err(|_| {
2312                                SerializeError::Internal(Cow::Borrowed(
2313                                    "field value is not a dynamic value",
2314                                ))
2315                            })?;
2316                            serialize_dynamic_with_shape(
2317                                serializer,
2318                                field_dyn,
2319                                field.shape(),
2320                                value_shape,
2321                            )?;
2322                        }
2323                    }
2324                }
2325
2326                Ok(())
2327            } else {
2328                // Externally tagged representation
2329                serializer.begin_struct().map_err(SerializeError::Backend)?;
2330                serializer
2331                    .field_key(variant.effective_name())
2332                    .map_err(SerializeError::Backend)?;
2333
2334                match variant.data.kind {
2335                    StructKind::Unit => {
2336                        serializer
2337                            .scalar(ScalarValue::Null)
2338                            .map_err(SerializeError::Backend)?;
2339                    }
2340                    StructKind::TupleStruct | StructKind::Tuple => {
2341                        if variant.data.fields.len() == 1 {
2342                            serialize_dynamic_with_shape(
2343                                serializer,
2344                                payload_dyn,
2345                                variant.data.fields[0].shape(),
2346                                value_shape,
2347                            )?;
2348                        } else {
2349                            serializer.begin_seq().map_err(SerializeError::Backend)?;
2350                            let iter = payload_dyn.array_iter().ok_or_else(|| {
2351                                SerializeError::Unsupported(Cow::Borrowed(
2352                                    "expected array for tuple variant",
2353                                ))
2354                            })?;
2355                            for (field, elem) in variant.data.fields.iter().zip(iter) {
2356                                let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2357                                    SerializeError::Internal(Cow::Borrowed(
2358                                        "element is not a dynamic value",
2359                                    ))
2360                                })?;
2361                                serialize_dynamic_with_shape(
2362                                    serializer,
2363                                    elem_dyn,
2364                                    field.shape(),
2365                                    value_shape,
2366                                )?;
2367                            }
2368                            serializer.end_seq().map_err(SerializeError::Backend)?;
2369                        }
2370                    }
2371                    StructKind::Struct => {
2372                        serializer.begin_struct().map_err(SerializeError::Backend)?;
2373                        for field in variant.data.fields {
2374                            let field_value =
2375                                payload_dyn.object_get(field.name).ok_or_else(|| {
2376                                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2377                                        "missing field '{}'",
2378                                        field.name
2379                                    )))
2380                                })?;
2381                            serializer
2382                                .field_key(field.name)
2383                                .map_err(SerializeError::Backend)?;
2384                            let field_dyn = field_value.into_dynamic_value().map_err(|_| {
2385                                SerializeError::Internal(Cow::Borrowed(
2386                                    "field is not a dynamic value",
2387                                ))
2388                            })?;
2389                            serialize_dynamic_with_shape(
2390                                serializer,
2391                                field_dyn,
2392                                field.shape(),
2393                                value_shape,
2394                            )?;
2395                        }
2396                        serializer.end_struct().map_err(SerializeError::Backend)?;
2397                    }
2398                }
2399
2400                serializer.end_struct().map_err(SerializeError::Backend)
2401            }
2402        }
2403
2404        // Null could be a unit variant named "Null" (untagged representation)
2405        DynValueKind::Null => {
2406            // Check if there's a Null variant or fallback for Option-like enums
2407            // Note: we match against the Rust name (v.name) since these are well-known Rust identifiers
2408            if let Some((variant_index, variant)) = enum_def
2409                .variants
2410                .iter()
2411                .enumerate()
2412                .find(|(_, v)| v.name.eq_ignore_ascii_case("null") || v.name == "None")
2413            {
2414                if use_index {
2415                    serializer
2416                        .begin_enum_variant(variant_index, variant.effective_name())
2417                        .map_err(SerializeError::Backend)?;
2418                    Ok(())
2419                } else {
2420                    serializer
2421                        .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
2422                        .map_err(SerializeError::Backend)
2423                }
2424            } else {
2425                Err(SerializeError::Unsupported(Cow::Borrowed(
2426                    "null value for enum without null/None variant",
2427                )))
2428            }
2429        }
2430
2431        _ => {
2432            // For untagged enums, we might need to try matching variants
2433            // This is a simplified implementation - could be extended
2434            let _ = target_shape; // Suppress unused warning
2435            Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2436                "unsupported dynamic value kind {:?} for enum serialization",
2437                dynamic.kind()
2438            ))))
2439        }
2440    }
2441}