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                    // Check for field-level proxy
1315                    if let Some(field_def) = variant.data.fields.first()
1316                        && let Some(proxy_def) =
1317                            field_def.effective_proxy(serializer.format_namespace())
1318                    {
1319                        serialize_via_proxy(serializer, inner, proxy_def)?;
1320                    } else {
1321                        shared_serialize(serializer, inner)?;
1322                    }
1323                } else {
1324                    serializer.begin_seq().map_err(SerializeError::Backend)?;
1325                    for idx in 0..field_count {
1326                        let inner = enum_
1327                            .field(idx)
1328                            .map_err(|_| {
1329                                SerializeError::Internal(Cow::Borrowed(
1330                                    "variant field lookup failed",
1331                                ))
1332                            })?
1333                            .ok_or(SerializeError::Internal(Cow::Borrowed(
1334                                "variant field missing while iterating tuple fields",
1335                            )))?;
1336                        // Check for field-level proxy
1337                        if let Some(field_def) = variant.data.fields.get(idx)
1338                            && let Some(proxy_def) =
1339                                field_def.effective_proxy(serializer.format_namespace())
1340                        {
1341                            serialize_via_proxy(serializer, inner, proxy_def)?;
1342                        } else {
1343                            shared_serialize(serializer, inner)?;
1344                        }
1345                    }
1346                    serializer.end_seq().map_err(SerializeError::Backend)?;
1347                }
1348
1349                serializer.end_struct().map_err(SerializeError::Backend)?;
1350                Ok(())
1351            }
1352            StructKind::Struct => {
1353                let field_mode = serializer.struct_field_mode();
1354                serializer.begin_struct().map_err(SerializeError::Backend)?;
1355                serializer
1356                    .field_key(variant.effective_name())
1357                    .map_err(SerializeError::Backend)?;
1358
1359                serializer.begin_struct().map_err(SerializeError::Backend)?;
1360                let mut fields: alloc::vec::Vec<_> = if field_mode == StructFieldMode::Unnamed {
1361                    enum_.fields_for_binary_serialize().collect()
1362                } else {
1363                    enum_.fields_for_serialize().collect()
1364                };
1365                sort_fields_if_needed(serializer, &mut fields);
1366                for (field_item, field_value) in fields {
1367                    serializer
1368                        .field_metadata(&field_item)
1369                        .map_err(SerializeError::Backend)?;
1370                    if field_mode == StructFieldMode::Named {
1371                        serializer
1372                            .field_key(field_item.effective_name())
1373                            .map_err(SerializeError::Backend)?;
1374                    }
1375                    // Check for field-level proxy
1376                    if let Some(proxy_def) = field_item
1377                        .field
1378                        .and_then(|f| f.effective_proxy(serializer.format_namespace()))
1379                    {
1380                        serialize_via_proxy(serializer, field_value, proxy_def)?;
1381                    } else {
1382                        shared_serialize(serializer, field_value)?;
1383                    }
1384                }
1385                serializer.end_struct().map_err(SerializeError::Backend)?;
1386
1387                serializer.end_struct().map_err(SerializeError::Backend)?;
1388                Ok(())
1389            }
1390        };
1391    }
1392
1393    Err(SerializeError::Unsupported(Cow::Borrowed(
1394        "unsupported value kind for serialization",
1395    )))
1396}
1397
1398fn serialize_dynamic_value<'mem, 'facet, S>(
1399    serializer: &mut S,
1400    dynamic: facet_reflect::PeekDynamicValue<'mem, 'facet>,
1401) -> Result<(), SerializeError<S::Error>>
1402where
1403    S: FormatSerializer,
1404{
1405    let tagged = serializer.dynamic_value_encoding() == DynamicValueEncoding::Tagged;
1406
1407    match dynamic.kind() {
1408        DynValueKind::Null => {
1409            if tagged {
1410                serializer
1411                    .dynamic_value_tag(DynamicValueTag::Null)
1412                    .map_err(SerializeError::Backend)?;
1413            }
1414            serializer
1415                .scalar(ScalarValue::Null)
1416                .map_err(SerializeError::Backend)
1417        }
1418        DynValueKind::Bool => {
1419            let value = dynamic.as_bool().ok_or_else(|| {
1420                SerializeError::Internal(Cow::Borrowed("dynamic bool missing value"))
1421            })?;
1422            if tagged {
1423                serializer
1424                    .dynamic_value_tag(DynamicValueTag::Bool)
1425                    .map_err(SerializeError::Backend)?;
1426            }
1427            serializer
1428                .scalar(ScalarValue::Bool(value))
1429                .map_err(SerializeError::Backend)
1430        }
1431        DynValueKind::Number => {
1432            if let Some(n) = dynamic.as_i64() {
1433                if tagged {
1434                    serializer
1435                        .dynamic_value_tag(DynamicValueTag::I64)
1436                        .map_err(SerializeError::Backend)?;
1437                }
1438                serializer
1439                    .scalar(ScalarValue::I64(n))
1440                    .map_err(SerializeError::Backend)
1441            } else if let Some(n) = dynamic.as_u64() {
1442                if tagged {
1443                    serializer
1444                        .dynamic_value_tag(DynamicValueTag::U64)
1445                        .map_err(SerializeError::Backend)?;
1446                }
1447                serializer
1448                    .scalar(ScalarValue::U64(n))
1449                    .map_err(SerializeError::Backend)
1450            } else if let Some(n) = dynamic.as_f64() {
1451                if tagged {
1452                    serializer
1453                        .dynamic_value_tag(DynamicValueTag::F64)
1454                        .map_err(SerializeError::Backend)?;
1455                }
1456                serializer
1457                    .scalar(ScalarValue::F64(n))
1458                    .map_err(SerializeError::Backend)
1459            } else {
1460                Err(SerializeError::Unsupported(Cow::Borrowed(
1461                    "dynamic number not representable",
1462                )))
1463            }
1464        }
1465        DynValueKind::String => {
1466            let value = dynamic.as_str().ok_or_else(|| {
1467                SerializeError::Internal(Cow::Borrowed("dynamic string missing value"))
1468            })?;
1469            if tagged {
1470                serializer
1471                    .dynamic_value_tag(DynamicValueTag::String)
1472                    .map_err(SerializeError::Backend)?;
1473            }
1474            serializer
1475                .scalar(ScalarValue::Str(Cow::Borrowed(value)))
1476                .map_err(SerializeError::Backend)
1477        }
1478        DynValueKind::Bytes => {
1479            let value = dynamic.as_bytes().ok_or_else(|| {
1480                SerializeError::Internal(Cow::Borrowed("dynamic bytes missing value"))
1481            })?;
1482            if tagged {
1483                serializer
1484                    .dynamic_value_tag(DynamicValueTag::Bytes)
1485                    .map_err(SerializeError::Backend)?;
1486            }
1487            serializer
1488                .scalar(ScalarValue::Bytes(Cow::Borrowed(value)))
1489                .map_err(SerializeError::Backend)
1490        }
1491        DynValueKind::Array => {
1492            let len = dynamic.array_len().ok_or_else(|| {
1493                SerializeError::Internal(Cow::Borrowed("dynamic array missing length"))
1494            })?;
1495            if tagged {
1496                serializer
1497                    .dynamic_value_tag(DynamicValueTag::Array)
1498                    .map_err(SerializeError::Backend)?;
1499            }
1500            serializer
1501                .begin_seq_with_len(len)
1502                .map_err(SerializeError::Backend)?;
1503            if let Some(iter) = dynamic.array_iter() {
1504                for item in iter {
1505                    shared_serialize(serializer, item)?;
1506                }
1507            }
1508            serializer.end_seq().map_err(SerializeError::Backend)
1509        }
1510        DynValueKind::Object => {
1511            let len = dynamic.object_len().ok_or_else(|| {
1512                SerializeError::Internal(Cow::Borrowed("dynamic object missing length"))
1513            })?;
1514            if tagged {
1515                serializer
1516                    .dynamic_value_tag(DynamicValueTag::Object)
1517                    .map_err(SerializeError::Backend)?;
1518            }
1519            match serializer.map_encoding() {
1520                MapEncoding::Pairs => {
1521                    serializer
1522                        .begin_map_with_len(len)
1523                        .map_err(SerializeError::Backend)?;
1524                    if let Some(iter) = dynamic.object_iter() {
1525                        for (key, value) in iter {
1526                            serializer
1527                                .scalar(ScalarValue::Str(Cow::Borrowed(key)))
1528                                .map_err(SerializeError::Backend)?;
1529                            shared_serialize(serializer, value)?;
1530                        }
1531                    }
1532                    serializer.end_map().map_err(SerializeError::Backend)
1533                }
1534                MapEncoding::Struct => {
1535                    serializer.begin_struct().map_err(SerializeError::Backend)?;
1536                    if let Some(iter) = dynamic.object_iter() {
1537                        for (key, value) in iter {
1538                            serializer.field_key(key).map_err(SerializeError::Backend)?;
1539                            shared_serialize(serializer, value)?;
1540                        }
1541                    }
1542                    serializer.end_struct().map_err(SerializeError::Backend)
1543                }
1544            }
1545        }
1546        DynValueKind::DateTime => {
1547            let dt = dynamic.as_datetime().ok_or_else(|| {
1548                SerializeError::Internal(Cow::Borrowed("dynamic datetime missing value"))
1549            })?;
1550            if tagged {
1551                serializer
1552                    .dynamic_value_tag(DynamicValueTag::DateTime)
1553                    .map_err(SerializeError::Backend)?;
1554            }
1555            let s = format_dyn_datetime(dt);
1556            serializer
1557                .scalar(ScalarValue::Str(Cow::Owned(s)))
1558                .map_err(SerializeError::Backend)
1559        }
1560        DynValueKind::QName | DynValueKind::Uuid => Err(SerializeError::Unsupported(
1561            Cow::Borrowed("dynamic QName/Uuid serialization is not supported"),
1562        )),
1563    }
1564}
1565
1566fn format_dyn_datetime(
1567    (year, month, day, hour, minute, second, nanos, kind): (
1568        i32,
1569        u8,
1570        u8,
1571        u8,
1572        u8,
1573        u8,
1574        u32,
1575        DynDateTimeKind,
1576    ),
1577) -> String {
1578    let mut out = String::new();
1579    match kind {
1580        DynDateTimeKind::Offset { offset_minutes } => {
1581            let _ = write!(
1582                out,
1583                "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
1584                year, month, day, hour, minute, second
1585            );
1586            if nanos > 0 {
1587                let _ = write!(out, ".{:09}", nanos);
1588            }
1589            if offset_minutes == 0 {
1590                out.push('Z');
1591            } else {
1592                let sign = if offset_minutes >= 0 { '+' } else { '-' };
1593                let abs = offset_minutes.unsigned_abs();
1594                let _ = write!(out, "{}{:02}:{:02}", sign, abs / 60, abs % 60);
1595            }
1596        }
1597        DynDateTimeKind::LocalDateTime => {
1598            let _ = write!(
1599                out,
1600                "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
1601                year, month, day, hour, minute, second
1602            );
1603            if nanos > 0 {
1604                let _ = write!(out, ".{:09}", nanos);
1605            }
1606        }
1607        DynDateTimeKind::LocalDate => {
1608            let _ = write!(out, "{:04}-{:02}-{:02}", year, month, day);
1609        }
1610        DynDateTimeKind::LocalTime => {
1611            let _ = write!(out, "{:02}:{:02}:{:02}", hour, minute, second);
1612            if nanos > 0 {
1613                let _ = write!(out, ".{:09}", nanos);
1614            }
1615        }
1616    }
1617    out
1618}
1619
1620fn serialize_numeric_enum<S>(
1621    serializer: &mut S,
1622    variant: &'static facet_core::Variant,
1623) -> Result<(), SerializeError<S::Error>>
1624where
1625    S: FormatSerializer,
1626{
1627    let discriminant = variant
1628        .discriminant
1629        .ok_or(SerializeError::Unsupported(Cow::Borrowed(
1630            "Enum without a discriminant",
1631        )))?;
1632    serializer
1633        .scalar(ScalarValue::I64(discriminant))
1634        .map_err(SerializeError::Backend)
1635}
1636
1637fn serialize_untagged_enum<'mem, 'facet, S>(
1638    serializer: &mut S,
1639    enum_: facet_reflect::PeekEnum<'mem, 'facet>,
1640    variant: &'static facet_core::Variant,
1641) -> Result<(), SerializeError<S::Error>>
1642where
1643    S: FormatSerializer,
1644{
1645    match variant.data.kind {
1646        StructKind::Unit => serializer
1647            .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
1648            .map_err(SerializeError::Backend),
1649        StructKind::TupleStruct | StructKind::Tuple => {
1650            let field_count = variant.data.fields.len();
1651            if field_count == 1 {
1652                let inner = enum_
1653                    .field(0)
1654                    .map_err(|_| {
1655                        SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
1656                    })?
1657                    .ok_or(SerializeError::Internal(Cow::Borrowed(
1658                        "variant reported 1 field but field(0) returned None",
1659                    )))?;
1660                shared_serialize(serializer, inner)
1661            } else {
1662                serializer.begin_seq().map_err(SerializeError::Backend)?;
1663                for idx in 0..field_count {
1664                    let inner = enum_
1665                        .field(idx)
1666                        .map_err(|_| {
1667                            SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
1668                        })?
1669                        .ok_or(SerializeError::Internal(Cow::Borrowed(
1670                            "variant field missing while iterating tuple fields",
1671                        )))?;
1672                    shared_serialize(serializer, inner)?;
1673                }
1674                serializer.end_seq().map_err(SerializeError::Backend)?;
1675                Ok(())
1676            }
1677        }
1678        StructKind::Struct => {
1679            let field_mode = serializer.struct_field_mode();
1680            serializer.begin_struct().map_err(SerializeError::Backend)?;
1681            let mut fields: alloc::vec::Vec<_> = if field_mode == StructFieldMode::Unnamed {
1682                enum_.fields_for_binary_serialize().collect()
1683            } else {
1684                enum_.fields_for_serialize().collect()
1685            };
1686            sort_fields_if_needed(serializer, &mut fields);
1687            for (field_item, field_value) in fields {
1688                serializer
1689                    .field_metadata(&field_item)
1690                    .map_err(SerializeError::Backend)?;
1691                if field_mode == StructFieldMode::Named {
1692                    serializer
1693                        .field_key(field_item.effective_name())
1694                        .map_err(SerializeError::Backend)?;
1695                }
1696                // Check for field-level proxy
1697                if let Some(proxy_def) = field_item
1698                    .field
1699                    .and_then(|f| f.effective_proxy(serializer.format_namespace()))
1700                {
1701                    serialize_via_proxy(serializer, field_value, proxy_def)?;
1702                } else {
1703                    shared_serialize(serializer, field_value)?;
1704                }
1705            }
1706            serializer.end_struct().map_err(SerializeError::Backend)?;
1707            Ok(())
1708        }
1709    }
1710}
1711
1712/// Dereference a pointer/reference (Box, Arc, etc.) to get the underlying value
1713fn deref_if_pointer<'mem, 'facet>(peek: Peek<'mem, 'facet>) -> Peek<'mem, 'facet> {
1714    if let Ok(ptr) = peek.into_pointer()
1715        && let Some(target) = ptr.borrow_inner()
1716    {
1717        return deref_if_pointer(target);
1718    }
1719    peek
1720}
1721
1722/// Serialize a value through its proxy type.
1723///
1724/// # Safety note
1725/// This function requires unsafe code to:
1726/// - Allocate memory for the proxy type
1727/// - Call the conversion function from target to proxy
1728/// - Drop the proxy value after serialization
1729#[allow(unsafe_code)]
1730fn serialize_via_proxy<'mem, 'facet, S>(
1731    serializer: &mut S,
1732    value: Peek<'mem, 'facet>,
1733    proxy_def: &'static facet_core::ProxyDef,
1734) -> Result<(), SerializeError<S::Error>>
1735where
1736    S: FormatSerializer,
1737{
1738    use facet_core::PtrUninit;
1739
1740    let proxy_shape = proxy_def.shape;
1741    let proxy_layout = proxy_shape.layout.sized_layout().map_err(|_| {
1742        SerializeError::Unsupported(Cow::Borrowed("proxy type must be sized for serialization"))
1743    })?;
1744
1745    // Allocate memory for the proxy value
1746    let proxy_mem = unsafe { alloc::alloc::alloc(proxy_layout) };
1747    if proxy_mem.is_null() {
1748        return Err(SerializeError::Internal(Cow::Borrowed(
1749            "failed to allocate proxy memory",
1750        )));
1751    }
1752
1753    // Convert target → proxy
1754    let proxy_uninit = PtrUninit::new(proxy_mem);
1755    let convert_result = unsafe { (proxy_def.convert_out)(value.data(), proxy_uninit) };
1756
1757    let proxy_ptr = match convert_result {
1758        Ok(ptr) => ptr,
1759        Err(msg) => {
1760            unsafe { alloc::alloc::dealloc(proxy_mem, proxy_layout) };
1761            return Err(SerializeError::Unsupported(Cow::Owned(msg)));
1762        }
1763    };
1764
1765    // Create a Peek to the proxy value and serialize it
1766    let proxy_peek = unsafe { Peek::unchecked_new(proxy_ptr.as_const(), proxy_shape) };
1767    let result = shared_serialize(serializer, proxy_peek);
1768
1769    // Clean up: drop the proxy value and deallocate
1770    unsafe {
1771        let _ = proxy_shape.call_drop_in_place(proxy_ptr);
1772        alloc::alloc::dealloc(proxy_mem, proxy_layout);
1773    }
1774
1775    result
1776}
1777
1778// ─────────────────────────────────────────────────────────────────────────────
1779// Shape-guided serialization of dynamic values
1780// ─────────────────────────────────────────────────────────────────────────────
1781
1782/// Serialize a dynamic value (like `facet_value::Value`) according to a target shape.
1783///
1784/// This is the inverse of `FormatDeserializer::deserialize_with_shape`. It allows serializing
1785/// a `Value` as if it were a typed value matching the shape, without the dynamic value's
1786/// type discriminants.
1787///
1788/// This is useful for non-self-describing formats like postcard where you want to:
1789/// 1. Parse JSON into a `Value`
1790/// 2. Serialize it to postcard bytes matching a typed schema
1791///
1792/// # Arguments
1793///
1794/// * `serializer` - The format serializer to use
1795/// * `value` - A `Peek` into a dynamic value type (like `facet_value::Value`)
1796/// * `target_shape` - The shape describing the expected wire format
1797///
1798/// # Errors
1799///
1800/// Returns an error if:
1801/// - The value is not a dynamic value type
1802/// - The value's structure doesn't match the target shape
1803pub fn serialize_value_with_shape<S>(
1804    serializer: &mut S,
1805    value: Peek<'_, '_>,
1806    target_shape: &'static Shape,
1807) -> Result<(), SerializeError<S::Error>>
1808where
1809    S: FormatSerializer,
1810{
1811    let dynamic = value.into_dynamic_value().map_err(|_| {
1812        SerializeError::Unsupported(Cow::Borrowed(
1813            "serialize_value_with_shape requires a DynamicValue type",
1814        ))
1815    })?;
1816
1817    serialize_dynamic_with_shape(serializer, dynamic, target_shape, value.shape())
1818}
1819
1820fn serialize_dynamic_with_shape<S>(
1821    serializer: &mut S,
1822    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1823    target_shape: &'static Shape,
1824    value_shape: &'static Shape,
1825) -> Result<(), SerializeError<S::Error>>
1826where
1827    S: FormatSerializer,
1828{
1829    use facet_core::{ListDef, OptionDef, ScalarType as CoreScalarType, Type, UserType};
1830
1831    // Handle smart pointers - unwrap to the inner shape
1832    if let Def::Pointer(ptr_def) = target_shape.def
1833        && let Some(pointee) = ptr_def.pointee
1834    {
1835        return serialize_dynamic_with_shape(serializer, dynamic, pointee, value_shape);
1836    }
1837
1838    // Handle transparent wrappers via .inner
1839    if let Some(inner_shape) = target_shape.inner {
1840        // Skip collection types that have .inner for variance but aren't transparent wrappers
1841        if !matches!(
1842            target_shape.def,
1843            Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
1844        ) {
1845            return serialize_dynamic_with_shape(serializer, dynamic, inner_shape, value_shape);
1846        }
1847    }
1848
1849    // Handle Option<T>
1850    if let Def::Option(OptionDef { t: inner_shape, .. }) = target_shape.def {
1851        return serialize_option_from_dynamic(serializer, dynamic, inner_shape, value_shape);
1852    }
1853
1854    // Handle List/Vec
1855    if let Def::List(ListDef { t: item_shape, .. }) = target_shape.def {
1856        return serialize_list_from_dynamic(serializer, dynamic, item_shape, value_shape);
1857    }
1858
1859    // Handle Array [T; N]
1860    if let Def::Array(array_def) = target_shape.def {
1861        return serialize_array_from_dynamic(serializer, dynamic, array_def.t, value_shape);
1862    }
1863
1864    // Handle Map
1865    if let Def::Map(map_def) = target_shape.def {
1866        return serialize_map_from_dynamic(serializer, dynamic, map_def.k, map_def.v, value_shape);
1867    }
1868
1869    // Handle scalars
1870    if let Some(scalar_type) = CoreScalarType::try_from_shape(target_shape) {
1871        return serialize_scalar_from_dynamic(serializer, dynamic, scalar_type);
1872    }
1873
1874    // Handle structs and enums by Type
1875    match target_shape.ty {
1876        Type::User(UserType::Struct(struct_def)) => {
1877            serialize_struct_from_dynamic(serializer, dynamic, struct_def, value_shape)
1878        }
1879        Type::User(UserType::Enum(enum_def)) => {
1880            serialize_enum_from_dynamic(serializer, dynamic, enum_def, target_shape, value_shape)
1881        }
1882        _ => Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
1883            "unsupported target shape for serialize_value_with_shape: {}",
1884            target_shape
1885        )))),
1886    }
1887}
1888
1889fn serialize_option_from_dynamic<S>(
1890    serializer: &mut S,
1891    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1892    inner_shape: &'static Shape,
1893    value_shape: &'static Shape,
1894) -> Result<(), SerializeError<S::Error>>
1895where
1896    S: FormatSerializer,
1897{
1898    if dynamic.kind() == DynValueKind::Null {
1899        serializer.serialize_none().map_err(SerializeError::Backend)
1900    } else {
1901        serializer
1902            .begin_option_some()
1903            .map_err(SerializeError::Backend)?;
1904        serialize_dynamic_with_shape(serializer, dynamic, inner_shape, value_shape)
1905    }
1906}
1907
1908fn serialize_list_from_dynamic<S>(
1909    serializer: &mut S,
1910    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1911    item_shape: &'static Shape,
1912    value_shape: &'static Shape,
1913) -> Result<(), SerializeError<S::Error>>
1914where
1915    S: FormatSerializer,
1916{
1917    let len = dynamic.array_len().ok_or_else(|| {
1918        SerializeError::Unsupported(Cow::Borrowed(
1919            "expected array value for list/vec target shape",
1920        ))
1921    })?;
1922
1923    serializer
1924        .begin_seq_with_len(len)
1925        .map_err(SerializeError::Backend)?;
1926
1927    if let Some(iter) = dynamic.array_iter() {
1928        for elem in iter {
1929            let elem_dyn = elem.into_dynamic_value().map_err(|_| {
1930                SerializeError::Internal(Cow::Borrowed("array element is not a dynamic value"))
1931            })?;
1932            serialize_dynamic_with_shape(serializer, elem_dyn, item_shape, value_shape)?;
1933        }
1934    }
1935
1936    serializer.end_seq().map_err(SerializeError::Backend)
1937}
1938
1939fn serialize_array_from_dynamic<S>(
1940    serializer: &mut S,
1941    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1942    item_shape: &'static Shape,
1943    value_shape: &'static Shape,
1944) -> Result<(), SerializeError<S::Error>>
1945where
1946    S: FormatSerializer,
1947{
1948    // Arrays don't have length prefix in postcard
1949    serializer.begin_seq().map_err(SerializeError::Backend)?;
1950
1951    if let Some(iter) = dynamic.array_iter() {
1952        for elem in iter {
1953            let elem_dyn = elem.into_dynamic_value().map_err(|_| {
1954                SerializeError::Internal(Cow::Borrowed("array element is not a dynamic value"))
1955            })?;
1956            serialize_dynamic_with_shape(serializer, elem_dyn, item_shape, value_shape)?;
1957        }
1958    }
1959
1960    serializer.end_seq().map_err(SerializeError::Backend)
1961}
1962
1963fn serialize_map_from_dynamic<S>(
1964    serializer: &mut S,
1965    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
1966    key_shape: &'static Shape,
1967    value_shape_inner: &'static Shape,
1968    value_shape: &'static Shape,
1969) -> Result<(), SerializeError<S::Error>>
1970where
1971    S: FormatSerializer,
1972{
1973    let len = dynamic.object_len().ok_or_else(|| {
1974        SerializeError::Unsupported(Cow::Borrowed("expected object value for map target shape"))
1975    })?;
1976
1977    match serializer.map_encoding() {
1978        MapEncoding::Pairs => {
1979            serializer
1980                .begin_map_with_len(len)
1981                .map_err(SerializeError::Backend)?;
1982
1983            if let Some(iter) = dynamic.object_iter() {
1984                for (key, val) in iter {
1985                    // Serialize key according to key_shape
1986                    serialize_string_as_scalar(serializer, key, key_shape)?;
1987                    // Serialize value
1988                    let val_dyn = val.into_dynamic_value().map_err(|_| {
1989                        SerializeError::Internal(Cow::Borrowed(
1990                            "object value is not a dynamic value",
1991                        ))
1992                    })?;
1993                    serialize_dynamic_with_shape(
1994                        serializer,
1995                        val_dyn,
1996                        value_shape_inner,
1997                        value_shape,
1998                    )?;
1999                }
2000            }
2001
2002            serializer.end_map().map_err(SerializeError::Backend)
2003        }
2004        MapEncoding::Struct => {
2005            serializer.begin_struct().map_err(SerializeError::Backend)?;
2006
2007            if let Some(iter) = dynamic.object_iter() {
2008                for (key, val) in iter {
2009                    serializer.field_key(key).map_err(SerializeError::Backend)?;
2010                    let val_dyn = val.into_dynamic_value().map_err(|_| {
2011                        SerializeError::Internal(Cow::Borrowed(
2012                            "object value is not a dynamic value",
2013                        ))
2014                    })?;
2015                    serialize_dynamic_with_shape(
2016                        serializer,
2017                        val_dyn,
2018                        value_shape_inner,
2019                        value_shape,
2020                    )?;
2021                }
2022            }
2023
2024            serializer.end_struct().map_err(SerializeError::Backend)
2025        }
2026    }
2027}
2028
2029fn serialize_string_as_scalar<S>(
2030    serializer: &mut S,
2031    s: &str,
2032    _key_shape: &'static Shape,
2033) -> Result<(), SerializeError<S::Error>>
2034where
2035    S: FormatSerializer,
2036{
2037    // For now, serialize string keys directly
2038    // TODO: Handle non-string key types if needed
2039    serializer
2040        .scalar(ScalarValue::Str(Cow::Borrowed(s)))
2041        .map_err(SerializeError::Backend)
2042}
2043
2044fn serialize_scalar_from_dynamic<S>(
2045    serializer: &mut S,
2046    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2047    scalar_type: facet_core::ScalarType,
2048) -> Result<(), SerializeError<S::Error>>
2049where
2050    S: FormatSerializer,
2051{
2052    use facet_core::ScalarType as ST;
2053
2054    match scalar_type {
2055        ST::Unit => serializer
2056            .scalar(ScalarValue::Null)
2057            .map_err(SerializeError::Backend),
2058        ST::Bool => {
2059            let v = dynamic
2060                .as_bool()
2061                .ok_or_else(|| SerializeError::Unsupported(Cow::Borrowed("expected bool value")))?;
2062            serializer
2063                .scalar(ScalarValue::Bool(v))
2064                .map_err(SerializeError::Backend)
2065        }
2066        ST::Char => {
2067            let s = dynamic.as_str().ok_or_else(|| {
2068                SerializeError::Unsupported(Cow::Borrowed("expected string value for char"))
2069            })?;
2070            let c = s.chars().next().ok_or_else(|| {
2071                SerializeError::Unsupported(Cow::Borrowed("expected non-empty string for char"))
2072            })?;
2073            serializer
2074                .scalar(ScalarValue::Char(c))
2075                .map_err(SerializeError::Backend)
2076        }
2077        ST::Str | ST::String | ST::CowStr => {
2078            let s = dynamic.as_str().ok_or_else(|| {
2079                SerializeError::Unsupported(Cow::Borrowed("expected string value"))
2080            })?;
2081            serializer
2082                .scalar(ScalarValue::Str(Cow::Borrowed(s)))
2083                .map_err(SerializeError::Backend)
2084        }
2085        ST::U8 | ST::U16 | ST::U32 | ST::U64 | ST::USize => {
2086            let n = dynamic.as_u64().ok_or_else(|| {
2087                SerializeError::Unsupported(Cow::Borrowed("expected unsigned integer value"))
2088            })?;
2089            serializer
2090                .scalar(ScalarValue::U64(n))
2091                .map_err(SerializeError::Backend)
2092        }
2093        ST::U128 => {
2094            let n = dynamic.as_u64().ok_or_else(|| {
2095                SerializeError::Unsupported(Cow::Borrowed("expected unsigned integer value"))
2096            })?;
2097            serializer
2098                .scalar(ScalarValue::U128(n as u128))
2099                .map_err(SerializeError::Backend)
2100        }
2101        ST::I8 | ST::I16 | ST::I32 | ST::I64 | ST::ISize => {
2102            let n = dynamic.as_i64().ok_or_else(|| {
2103                SerializeError::Unsupported(Cow::Borrowed("expected signed integer value"))
2104            })?;
2105            serializer
2106                .scalar(ScalarValue::I64(n))
2107                .map_err(SerializeError::Backend)
2108        }
2109        ST::I128 => {
2110            let n = dynamic.as_i64().ok_or_else(|| {
2111                SerializeError::Unsupported(Cow::Borrowed("expected signed integer value"))
2112            })?;
2113            serializer
2114                .scalar(ScalarValue::I128(n as i128))
2115                .map_err(SerializeError::Backend)
2116        }
2117        ST::F32 | ST::F64 => {
2118            let n = dynamic.as_f64().ok_or_else(|| {
2119                SerializeError::Unsupported(Cow::Borrowed("expected float value"))
2120            })?;
2121            serializer
2122                .scalar(ScalarValue::F64(n))
2123                .map_err(SerializeError::Backend)
2124        }
2125        _ => Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2126            "unsupported scalar type: {:?}",
2127            scalar_type
2128        )))),
2129    }
2130}
2131
2132fn serialize_struct_from_dynamic<S>(
2133    serializer: &mut S,
2134    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2135    struct_def: facet_core::StructType,
2136    value_shape: &'static Shape,
2137) -> Result<(), SerializeError<S::Error>>
2138where
2139    S: FormatSerializer,
2140{
2141    let is_tuple = matches!(struct_def.kind, StructKind::Tuple | StructKind::TupleStruct);
2142
2143    if is_tuple {
2144        // For tuples, expect an array value
2145        serializer.begin_seq().map_err(SerializeError::Backend)?;
2146
2147        let iter = dynamic.array_iter().ok_or_else(|| {
2148            SerializeError::Unsupported(Cow::Borrowed("expected array value for tuple"))
2149        })?;
2150
2151        for (field, elem) in struct_def.fields.iter().zip(iter) {
2152            let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2153                SerializeError::Internal(Cow::Borrowed("tuple element is not a dynamic value"))
2154            })?;
2155            serialize_dynamic_with_shape(serializer, elem_dyn, field.shape(), value_shape)?;
2156        }
2157
2158        serializer.end_seq().map_err(SerializeError::Backend)
2159    } else {
2160        // For named structs, expect an object value
2161        let field_mode = serializer.struct_field_mode();
2162
2163        serializer.begin_struct().map_err(SerializeError::Backend)?;
2164
2165        for field in struct_def.fields {
2166            // Skip metadata fields
2167            if field.is_metadata() {
2168                continue;
2169            }
2170
2171            let field_name = field.name;
2172            let field_value = dynamic.object_get(field_name).ok_or_else(|| {
2173                SerializeError::Unsupported(Cow::Owned(alloc::format!(
2174                    "missing field '{}' in object",
2175                    field_name
2176                )))
2177            })?;
2178
2179            if field_mode == StructFieldMode::Named {
2180                serializer
2181                    .field_key(field_name)
2182                    .map_err(SerializeError::Backend)?;
2183            }
2184
2185            let field_dyn = field_value.into_dynamic_value().map_err(|_| {
2186                SerializeError::Internal(Cow::Borrowed("field value is not a dynamic value"))
2187            })?;
2188            serialize_dynamic_with_shape(serializer, field_dyn, field.shape(), value_shape)?;
2189        }
2190
2191        serializer.end_struct().map_err(SerializeError::Backend)
2192    }
2193}
2194
2195fn serialize_enum_from_dynamic<S>(
2196    serializer: &mut S,
2197    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2198    enum_def: facet_core::EnumType,
2199    target_shape: &'static Shape,
2200    value_shape: &'static Shape,
2201) -> Result<(), SerializeError<S::Error>>
2202where
2203    S: FormatSerializer,
2204{
2205    // For index-based encoding (postcard), we need to:
2206    // 1. Determine the variant from the Value
2207    // 2. Emit the variant index
2208    // 3. Serialize the variant's payload
2209
2210    let use_index = serializer.enum_variant_encoding() == EnumVariantEncoding::Index;
2211
2212    match dynamic.kind() {
2213        // Unit variant represented as a string
2214        DynValueKind::String => {
2215            let variant_name = dynamic.as_str().ok_or_else(|| {
2216                SerializeError::Internal(Cow::Borrowed("expected string for unit variant"))
2217            })?;
2218
2219            let (variant_index, variant) = enum_def
2220                .variants
2221                .iter()
2222                .enumerate()
2223                .find(|(_, v)| v.effective_name() == variant_name)
2224                .ok_or_else(|| {
2225                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2226                        "unknown variant '{}'",
2227                        variant_name
2228                    )))
2229                })?;
2230
2231            if use_index {
2232                serializer
2233                    .begin_enum_variant(variant_index, variant.effective_name())
2234                    .map_err(SerializeError::Backend)?;
2235                // Unit variant has no payload
2236                Ok(())
2237            } else {
2238                serializer
2239                    .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
2240                    .map_err(SerializeError::Backend)
2241            }
2242        }
2243
2244        // Variant with payload represented as object { "VariantName": payload }
2245        DynValueKind::Object => {
2246            // For externally tagged enums, the object has a single key = variant name
2247            let obj_len = dynamic.object_len().unwrap_or(0);
2248            if obj_len != 1 {
2249                return Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2250                    "expected single-key object for enum variant, got {} keys",
2251                    obj_len
2252                ))));
2253            }
2254
2255            let (variant_name, payload) = dynamic.object_get_entry(0).ok_or_else(|| {
2256                SerializeError::Internal(Cow::Borrowed("expected object entry for enum variant"))
2257            })?;
2258
2259            let (variant_index, variant) = enum_def
2260                .variants
2261                .iter()
2262                .enumerate()
2263                .find(|(_, v)| v.effective_name() == variant_name)
2264                .ok_or_else(|| {
2265                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2266                        "unknown variant '{}'",
2267                        variant_name
2268                    )))
2269                })?;
2270
2271            let payload_dyn = payload.into_dynamic_value().map_err(|_| {
2272                SerializeError::Internal(Cow::Borrowed("variant payload is not a dynamic value"))
2273            })?;
2274
2275            if use_index {
2276                serializer
2277                    .begin_enum_variant(variant_index, variant.effective_name())
2278                    .map_err(SerializeError::Backend)?;
2279
2280                // Serialize payload based on variant kind
2281                match variant.data.kind {
2282                    StructKind::Unit => {
2283                        // No payload to serialize
2284                    }
2285                    StructKind::TupleStruct | StructKind::Tuple => {
2286                        if variant.data.fields.len() == 1 {
2287                            // Newtype variant - serialize the single field directly
2288                            serialize_dynamic_with_shape(
2289                                serializer,
2290                                payload_dyn,
2291                                variant.data.fields[0].shape(),
2292                                value_shape,
2293                            )?;
2294                        } else {
2295                            // Multi-field tuple variant - expect array
2296                            let iter = payload_dyn.array_iter().ok_or_else(|| {
2297                                SerializeError::Unsupported(Cow::Borrowed(
2298                                    "expected array for tuple variant payload",
2299                                ))
2300                            })?;
2301
2302                            for (field, elem) in variant.data.fields.iter().zip(iter) {
2303                                let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2304                                    SerializeError::Internal(Cow::Borrowed(
2305                                        "tuple element is not a dynamic value",
2306                                    ))
2307                                })?;
2308                                serialize_dynamic_with_shape(
2309                                    serializer,
2310                                    elem_dyn,
2311                                    field.shape(),
2312                                    value_shape,
2313                                )?;
2314                            }
2315                        }
2316                    }
2317                    StructKind::Struct => {
2318                        // Struct variant - expect object
2319                        for field in variant.data.fields {
2320                            let field_value =
2321                                payload_dyn.object_get(field.name).ok_or_else(|| {
2322                                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2323                                        "missing field '{}' in struct variant",
2324                                        field.name
2325                                    )))
2326                                })?;
2327                            let field_dyn = field_value.into_dynamic_value().map_err(|_| {
2328                                SerializeError::Internal(Cow::Borrowed(
2329                                    "field value is not a dynamic value",
2330                                ))
2331                            })?;
2332                            serialize_dynamic_with_shape(
2333                                serializer,
2334                                field_dyn,
2335                                field.shape(),
2336                                value_shape,
2337                            )?;
2338                        }
2339                    }
2340                }
2341
2342                Ok(())
2343            } else {
2344                // Externally tagged representation
2345                serializer.begin_struct().map_err(SerializeError::Backend)?;
2346                serializer
2347                    .field_key(variant.effective_name())
2348                    .map_err(SerializeError::Backend)?;
2349
2350                match variant.data.kind {
2351                    StructKind::Unit => {
2352                        serializer
2353                            .scalar(ScalarValue::Null)
2354                            .map_err(SerializeError::Backend)?;
2355                    }
2356                    StructKind::TupleStruct | StructKind::Tuple => {
2357                        if variant.data.fields.len() == 1 {
2358                            serialize_dynamic_with_shape(
2359                                serializer,
2360                                payload_dyn,
2361                                variant.data.fields[0].shape(),
2362                                value_shape,
2363                            )?;
2364                        } else {
2365                            serializer.begin_seq().map_err(SerializeError::Backend)?;
2366                            let iter = payload_dyn.array_iter().ok_or_else(|| {
2367                                SerializeError::Unsupported(Cow::Borrowed(
2368                                    "expected array for tuple variant",
2369                                ))
2370                            })?;
2371                            for (field, elem) in variant.data.fields.iter().zip(iter) {
2372                                let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2373                                    SerializeError::Internal(Cow::Borrowed(
2374                                        "element is not a dynamic value",
2375                                    ))
2376                                })?;
2377                                serialize_dynamic_with_shape(
2378                                    serializer,
2379                                    elem_dyn,
2380                                    field.shape(),
2381                                    value_shape,
2382                                )?;
2383                            }
2384                            serializer.end_seq().map_err(SerializeError::Backend)?;
2385                        }
2386                    }
2387                    StructKind::Struct => {
2388                        serializer.begin_struct().map_err(SerializeError::Backend)?;
2389                        for field in variant.data.fields {
2390                            let field_value =
2391                                payload_dyn.object_get(field.name).ok_or_else(|| {
2392                                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2393                                        "missing field '{}'",
2394                                        field.name
2395                                    )))
2396                                })?;
2397                            serializer
2398                                .field_key(field.name)
2399                                .map_err(SerializeError::Backend)?;
2400                            let field_dyn = field_value.into_dynamic_value().map_err(|_| {
2401                                SerializeError::Internal(Cow::Borrowed(
2402                                    "field is not a dynamic value",
2403                                ))
2404                            })?;
2405                            serialize_dynamic_with_shape(
2406                                serializer,
2407                                field_dyn,
2408                                field.shape(),
2409                                value_shape,
2410                            )?;
2411                        }
2412                        serializer.end_struct().map_err(SerializeError::Backend)?;
2413                    }
2414                }
2415
2416                serializer.end_struct().map_err(SerializeError::Backend)
2417            }
2418        }
2419
2420        // Null could be a unit variant named "Null" (untagged representation)
2421        DynValueKind::Null => {
2422            // Check if there's a Null variant or fallback for Option-like enums
2423            // Note: we match against the Rust name (v.name) since these are well-known Rust identifiers
2424            if let Some((variant_index, variant)) = enum_def
2425                .variants
2426                .iter()
2427                .enumerate()
2428                .find(|(_, v)| v.name.eq_ignore_ascii_case("null") || v.name == "None")
2429            {
2430                if use_index {
2431                    serializer
2432                        .begin_enum_variant(variant_index, variant.effective_name())
2433                        .map_err(SerializeError::Backend)?;
2434                    Ok(())
2435                } else {
2436                    serializer
2437                        .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
2438                        .map_err(SerializeError::Backend)
2439                }
2440            } else {
2441                Err(SerializeError::Unsupported(Cow::Borrowed(
2442                    "null value for enum without null/None variant",
2443                )))
2444            }
2445        }
2446
2447        _ => {
2448            // For untagged enums, we might need to try matching variants
2449            // This is a simplified implementation - could be extended
2450            let _ = target_shape; // Suppress unused warning
2451            Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2452                "unsupported dynamic value kind {:?} for enum serialization",
2453                dynamic.kind()
2454            ))))
2455        }
2456    }
2457}