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