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    /// Recursively flattens a newtype variant's inner value into the current
1129    /// JSON object that already has `begin_struct` and the outer tag written.
1130    ///
1131    /// Three cases:
1132    /// 1. Inner value is a **struct** → emit its fields directly.
1133    /// 2. Inner value is an **internally-tagged enum** → emit its tag, then
1134    ///    handle its active variant (which may itself be a newtype, so recurse).
1135    /// 3. Inner value is a **scalar / unsupported type** → error, because
1136    ///    scalars cannot be flattened into an object.
1137    fn serialize_flattened_newtype_value<'mem, 'facet>(
1138        &mut self,
1139        value: Peek<'mem, 'facet>,
1140        used_tag_keys: &[&str],
1141    ) -> Result<(), SerializeError<S::Error>> {
1142        let shape = value.shape();
1143        let field_mode = self.serializer.struct_field_mode();
1144
1145        // Case 1: plain struct — flatten its fields into the enclosing object
1146        if let Ok(struct_) = value.into_struct() {
1147            let mut fields: alloc::vec::Vec<_> = if field_mode == StructFieldMode::Unnamed {
1148                struct_.fields_for_binary_serialize().collect()
1149            } else {
1150                struct_.fields_for_serialize().collect()
1151            };
1152            sort_fields_if_needed(self.serializer, &mut fields);
1153            for (field_item, field_value) in fields {
1154                self.serializer
1155                    .field_metadata(&field_item)
1156                    .map_err(SerializeError::Backend)?;
1157                if field_mode == StructFieldMode::Named {
1158                    self.serializer
1159                        .field_key(field_item.effective_name())
1160                        .map_err(SerializeError::Backend)?;
1161                }
1162                self.push(PathSegment::Field(Cow::Owned(
1163                    field_item.effective_name().to_string(),
1164                )));
1165                self.serialize_field_value(&field_item, field_value)?;
1166                self.pop();
1167            }
1168            return Ok(());
1169        }
1170
1171        // Case 2: internally-tagged enum — write its tag, then handle its variant
1172        if let Some(inner_tag) = shape.get_tag_attr()
1173            && shape.get_content_attr().is_none()
1174            && let Ok(inner_enum) = value.into_enum()
1175        {
1176            // Reject duplicate tag key names across nesting levels —
1177            // e.g. both outer and inner enum using #[facet(tag = "type")].
1178            // With a flat JSON object we cannot distinguish which "type"
1179            // value belongs to which level.
1180            if used_tag_keys.contains(&inner_tag) {
1181                return Err(SerializeError::Unsupported(
1182                    format!(
1183                        "nested internally-tagged enums use the same tag key \"{}\"; \
1184                         this is ambiguous when flattened into a single object",
1185                        inner_tag
1186                    )
1187                    .into(),
1188                ));
1189            }
1190
1191            let inner_variant = inner_enum
1192                .active_variant()
1193                .map_err(|e| SerializeError::Unsupported(Cow::Owned(e.to_string())))?;
1194
1195            // Write the inner enum's tag
1196            self.serializer
1197                .field_key(inner_tag)
1198                .map_err(SerializeError::Backend)?;
1199            self.serializer
1200                .scalar(ScalarValue::Str(Cow::Borrowed(
1201                    inner_variant.effective_name(),
1202                )))
1203                .map_err(SerializeError::Backend)?;
1204
1205            self.push(PathSegment::Variant(Cow::Borrowed(
1206                inner_variant.effective_name(),
1207            )));
1208
1209            match inner_variant.data.kind {
1210                StructKind::Unit => {}
1211                StructKind::Struct => {
1212                    let mut inner_fields: alloc::vec::Vec<_> =
1213                        if field_mode == StructFieldMode::Unnamed {
1214                            inner_enum.fields_for_binary_serialize().collect()
1215                        } else {
1216                            inner_enum.fields_for_serialize().collect()
1217                        };
1218                    sort_fields_if_needed(self.serializer, &mut inner_fields);
1219
1220                    for (field_item, field_value) in inner_fields {
1221                        self.serializer
1222                            .field_metadata(&field_item)
1223                            .map_err(SerializeError::Backend)?;
1224                        if field_mode == StructFieldMode::Named {
1225                            self.serializer
1226                                .field_key(field_item.effective_name())
1227                                .map_err(SerializeError::Backend)?;
1228                        }
1229                        self.push(PathSegment::Field(Cow::Owned(
1230                            field_item.effective_name().to_string(),
1231                        )));
1232                        self.serialize_field_value(&field_item, field_value)?;
1233                        self.pop();
1234                    }
1235                }
1236                StructKind::TupleStruct | StructKind::Tuple => {
1237                    // Inner variant is itself a newtype — recurse
1238                    if inner_variant.data.fields.len() != 1 {
1239                        self.pop();
1240                        return Err(SerializeError::Unsupported(Cow::Borrowed(
1241                            "internally tagged tuple variants with multiple fields are not supported",
1242                        )));
1243                    }
1244                    let nested_value = inner_enum
1245                        .field(0)
1246                        .map_err(|e| SerializeError::Unsupported(Cow::Owned(e.to_string())))?
1247                        .expect("single-field tuple variant should have field 0");
1248                    let mut inner_used_tag_keys = alloc::vec::Vec::from(used_tag_keys);
1249                    inner_used_tag_keys.push(inner_tag);
1250                    self.serialize_flattened_newtype_value(nested_value, &inner_used_tag_keys)?;
1251                }
1252            }
1253
1254            self.pop();
1255            return Ok(());
1256        }
1257
1258        // Case 3: scalar or other non-flattenable type
1259        Err(SerializeError::Unsupported(
1260            "internally-tagged enum with scalar newtype payload cannot be \
1261             flattened; use #[facet(content = \"...\")] for adjacently-tagged \
1262             representation"
1263                .into(),
1264        ))
1265    }
1266
1267    fn serialize_discriminant<'mem, 'facet>(
1268        &mut self,
1269        enum_: facet_reflect::PeekEnum<'mem, 'facet>,
1270    ) -> Result<(), SerializeError<S::Error>> {
1271        match enum_.ty().enum_repr {
1272            facet_core::EnumRepr::Rust => Err(SerializeError::Internal(Cow::Borrowed(
1273                "enum does not have an explicit representation",
1274            ))),
1275            facet_core::EnumRepr::RustNPO
1276            | facet_core::EnumRepr::U8
1277            | facet_core::EnumRepr::U16
1278            | facet_core::EnumRepr::U32
1279            | facet_core::EnumRepr::U64
1280            | facet_core::EnumRepr::USize => self
1281                .serializer
1282                .scalar(ScalarValue::U64(enum_.discriminant() as u64))
1283                .map_err(SerializeError::Backend),
1284            facet_core::EnumRepr::I8
1285            | facet_core::EnumRepr::I16
1286            | facet_core::EnumRepr::I32
1287            | facet_core::EnumRepr::I64
1288            | facet_core::EnumRepr::ISize => self
1289                .serializer
1290                .scalar(ScalarValue::I64(enum_.discriminant()))
1291                .map_err(SerializeError::Backend),
1292        }
1293    }
1294
1295    fn serialize_enum<'mem, 'facet>(
1296        &mut self,
1297        shape: &'static Shape,
1298        enum_: facet_reflect::PeekEnum<'mem, 'facet>,
1299    ) -> Result<(), SerializeError<S::Error>> {
1300        let variant = enum_.active_variant().map_err(|_| {
1301            SerializeError::Unsupported(Cow::Borrowed("opaque enum layout is unsupported"))
1302        })?;
1303
1304        self.serializer
1305            .variant_metadata(variant)
1306            .map_err(SerializeError::Backend)?;
1307
1308        // Cow-like enums serialize transparently
1309        if shape.is_cow() {
1310            let inner = enum_
1311                .field(0)
1312                .map_err(|_| {
1313                    SerializeError::Internal(Cow::Borrowed("cow variant field lookup failed"))
1314                })?
1315                .ok_or(SerializeError::Internal(Cow::Borrowed(
1316                    "cow variant has no field",
1317                )))?;
1318            return self.serialize_impl(inner);
1319        }
1320
1321        if self.serializer.enum_variant_encoding() == EnumVariantEncoding::Index {
1322            let variant_index = enum_.variant_index().map_err(|_| {
1323                SerializeError::Unsupported(Cow::Borrowed("opaque enum layout is unsupported"))
1324            })?;
1325            self.serializer
1326                .begin_enum_variant(variant_index, variant.name)
1327                .map_err(SerializeError::Backend)?;
1328
1329            self.push(PathSegment::Variant(Cow::Borrowed(variant.name)));
1330            let result = match variant.data.kind {
1331                StructKind::Unit => Ok(()),
1332                StructKind::TupleStruct | StructKind::Tuple | StructKind::Struct => {
1333                    for (idx, (field_item, field_value)) in
1334                        enum_.fields_for_binary_serialize().enumerate()
1335                    {
1336                        self.push(PathSegment::Index(idx));
1337                        self.serialize_field_value(&field_item, field_value)?;
1338                        self.pop();
1339                    }
1340                    Ok(())
1341                }
1342            };
1343            self.pop();
1344            return result;
1345        }
1346
1347        let numeric = shape.is_numeric();
1348        let untagged = shape.is_untagged();
1349        let tag = shape.get_tag_attr();
1350        let content = shape.get_content_attr();
1351
1352        if numeric && tag.is_none() {
1353            return serialize_numeric_enum(self.serializer, variant);
1354        }
1355        if untagged {
1356            self.push(PathSegment::Variant(Cow::Borrowed(
1357                variant.effective_name(),
1358            )));
1359            let result = self.serialize_untagged_enum(enum_, variant);
1360            self.pop();
1361            return result;
1362        }
1363
1364        // #[facet(other)] variants serialize as untagged UNLESS they have a #[facet(tag)] field.
1365        // When a tag field is present, the captured tag value should be serialized via
1366        // serialize_externally_tagged_enum, which knows how to extract and use that value.
1367        if variant.is_other() {
1368            let has_tag_field = variant.data.fields.iter().any(|f| f.is_variant_tag());
1369            if !has_tag_field {
1370                self.push(PathSegment::Variant(Cow::Borrowed(
1371                    variant.effective_name(),
1372                )));
1373                let result = self.serialize_untagged_enum(enum_, variant);
1374                self.pop();
1375                return result;
1376            }
1377        }
1378
1379        match (tag, content) {
1380            (Some(tag_key), None) => {
1381                // Internally tagged
1382                self.serializer
1383                    .begin_struct()
1384                    .map_err(SerializeError::Backend)?;
1385                self.serializer
1386                    .field_key(tag_key)
1387                    .map_err(SerializeError::Backend)?;
1388
1389                if numeric {
1390                    self.serialize_discriminant(enum_)?;
1391                } else {
1392                    self.serializer
1393                        .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
1394                        .map_err(SerializeError::Backend)?;
1395                }
1396
1397                self.push(PathSegment::Variant(Cow::Borrowed(
1398                    variant.effective_name(),
1399                )));
1400                let field_mode = self.serializer.struct_field_mode();
1401                match variant.data.kind {
1402                    StructKind::Unit => {}
1403                    StructKind::Struct => {
1404                        let mut fields: alloc::vec::Vec<_> =
1405                            if field_mode == StructFieldMode::Unnamed {
1406                                enum_.fields_for_binary_serialize().collect()
1407                            } else {
1408                                enum_.fields_for_serialize().collect()
1409                            };
1410                        sort_fields_if_needed(self.serializer, &mut fields);
1411                        for (field_item, field_value) in fields {
1412                            self.serializer
1413                                .field_metadata(&field_item)
1414                                .map_err(SerializeError::Backend)?;
1415                            if field_mode == StructFieldMode::Named {
1416                                self.serializer
1417                                    .field_key(field_item.effective_name())
1418                                    .map_err(SerializeError::Backend)?;
1419                            }
1420                            self.push(PathSegment::Field(Cow::Owned(
1421                                field_item.effective_name().to_string(),
1422                            )));
1423                            self.serialize_field_value(&field_item, field_value)?;
1424                            self.pop();
1425                        }
1426                    }
1427                    StructKind::TupleStruct | StructKind::Tuple => {
1428                        // Single-field tuple (newtype) variants get flattened into the
1429                        // enclosing tagged object. The inner value may be a struct, an
1430                        // internally-tagged enum, or a chain of newtype wrappers around
1431                        // one of those — we handle all cases recursively.
1432                        if variant.data.fields.len() != 1 {
1433                            self.pop();
1434                            return Err(SerializeError::Unsupported(Cow::Borrowed(
1435                                "internally tagged tuple variants with multiple fields are not supported",
1436                            )));
1437                        }
1438
1439                        let inner_value = enum_
1440                            .field(0)
1441                            .map_err(|e| SerializeError::Unsupported(Cow::Owned(e.to_string())))?
1442                            .expect("single-field tuple variant should have field 0");
1443
1444                        self.serialize_flattened_newtype_value(inner_value, &[tag_key])?;
1445                    }
1446                }
1447                self.pop();
1448
1449                self.serializer
1450                    .end_struct()
1451                    .map_err(SerializeError::Backend)?;
1452                return Ok(());
1453            }
1454            (Some(tag_key), Some(content_key)) => {
1455                // Adjacently tagged
1456                return self.serialize_adjacently_tagged_enum(
1457                    enum_,
1458                    variant,
1459                    tag_key,
1460                    content_key,
1461                    numeric,
1462                );
1463            }
1464            (None, Some(_)) => {
1465                return Err(SerializeError::Unsupported(Cow::Borrowed(
1466                    "adjacent content key set without tag key",
1467                )));
1468            }
1469            (None, None) => {}
1470        }
1471
1472        // Externally tagged (default)
1473        self.serialize_externally_tagged_enum(enum_, variant)
1474    }
1475
1476    fn serialize_adjacently_tagged_enum<'mem, 'facet>(
1477        &mut self,
1478        enum_: facet_reflect::PeekEnum<'mem, 'facet>,
1479        variant: &'static facet_core::Variant,
1480        tag_key: &'static str,
1481        content_key: &'static str,
1482        numeric: bool,
1483    ) -> Result<(), SerializeError<S::Error>> {
1484        let field_mode = self.serializer.struct_field_mode();
1485        self.serializer
1486            .begin_struct()
1487            .map_err(SerializeError::Backend)?;
1488        self.serializer
1489            .field_key(tag_key)
1490            .map_err(SerializeError::Backend)?;
1491
1492        if numeric {
1493            self.serialize_discriminant(enum_)?;
1494        } else {
1495            self.serializer
1496                .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
1497                .map_err(SerializeError::Backend)?;
1498        }
1499
1500        self.push(PathSegment::Variant(Cow::Borrowed(
1501            variant.effective_name(),
1502        )));
1503
1504        match variant.data.kind {
1505            StructKind::Unit => {}
1506            StructKind::Struct => {
1507                self.serializer
1508                    .field_key(content_key)
1509                    .map_err(SerializeError::Backend)?;
1510                self.serializer
1511                    .begin_struct()
1512                    .map_err(SerializeError::Backend)?;
1513                let mut fields: alloc::vec::Vec<_> = if field_mode == StructFieldMode::Unnamed {
1514                    enum_.fields_for_binary_serialize().collect()
1515                } else {
1516                    enum_.fields_for_serialize().collect()
1517                };
1518                sort_fields_if_needed(self.serializer, &mut fields);
1519                for (field_item, field_value) in fields {
1520                    self.serializer
1521                        .field_metadata(&field_item)
1522                        .map_err(SerializeError::Backend)?;
1523                    if field_mode == StructFieldMode::Named {
1524                        self.serializer
1525                            .field_key(field_item.effective_name())
1526                            .map_err(SerializeError::Backend)?;
1527                    }
1528                    self.push(PathSegment::Field(Cow::Owned(
1529                        field_item.effective_name().to_string(),
1530                    )));
1531                    self.serialize_field_value(&field_item, field_value)?;
1532                    self.pop();
1533                }
1534                self.serializer
1535                    .end_struct()
1536                    .map_err(SerializeError::Backend)?;
1537            }
1538            StructKind::TupleStruct | StructKind::Tuple => {
1539                self.serializer
1540                    .field_key(content_key)
1541                    .map_err(SerializeError::Backend)?;
1542
1543                let field_count = variant.data.fields.len();
1544                if field_count == 1 {
1545                    let inner = enum_
1546                        .field(0)
1547                        .map_err(|_| {
1548                            SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
1549                        })?
1550                        .ok_or(SerializeError::Internal(Cow::Borrowed(
1551                            "variant reported 1 field but field(0) returned None",
1552                        )))?;
1553                    let field_def = variant.data.fields.first().copied();
1554                    self.with_field_context(field_def, |this| this.serialize_impl(inner))?;
1555                } else {
1556                    self.serializer
1557                        .begin_seq()
1558                        .map_err(SerializeError::Backend)?;
1559                    for idx in 0..field_count {
1560                        let inner = enum_
1561                            .field(idx)
1562                            .map_err(|_| {
1563                                SerializeError::Internal(Cow::Borrowed(
1564                                    "variant field lookup failed",
1565                                ))
1566                            })?
1567                            .ok_or(SerializeError::Internal(Cow::Borrowed(
1568                                "variant field missing while iterating tuple fields",
1569                            )))?;
1570                        self.push(PathSegment::Index(idx));
1571                        let field_def = variant.data.fields.get(idx).copied();
1572                        self.with_field_context(field_def, |this| this.serialize_impl(inner))?;
1573                        self.pop();
1574                    }
1575                    self.serializer.end_seq().map_err(SerializeError::Backend)?;
1576                }
1577            }
1578        }
1579
1580        self.pop();
1581        self.serializer
1582            .end_struct()
1583            .map_err(SerializeError::Backend)?;
1584        Ok(())
1585    }
1586
1587    fn serialize_externally_tagged_enum<'mem, 'facet>(
1588        &mut self,
1589        enum_: facet_reflect::PeekEnum<'mem, 'facet>,
1590        variant: &'static facet_core::Variant,
1591    ) -> Result<(), SerializeError<S::Error>> {
1592        let field_mode = self.serializer.struct_field_mode();
1593
1594        // For #[facet(other)] variants with a #[facet(metadata = "tag")] field,
1595        // use the field's value as the tag name
1596        let tag_name: Cow<'_, str> = if variant.is_other() {
1597            let mut tag_value: Option<Cow<'_, str>> = None;
1598            let fields_iter: alloc::boxed::Box<
1599                dyn Iterator<Item = (facet_reflect::FieldItem, facet_reflect::Peek<'_, '_>)>,
1600            > = if field_mode == StructFieldMode::Unnamed {
1601                alloc::boxed::Box::new(enum_.fields_for_binary_serialize())
1602            } else {
1603                alloc::boxed::Box::new(enum_.fields_for_serialize())
1604            };
1605            for (field_item, field_value) in fields_iter {
1606                if let Some(field) = field_item.field
1607                    && field.is_variant_tag()
1608                {
1609                    if let Ok(opt) = field_value.into_option()
1610                        && let Some(inner) = opt.value()
1611                        && let Some(s) = inner.as_str()
1612                    {
1613                        tag_value = Some(Cow::Borrowed(s));
1614                    }
1615                    break;
1616                }
1617            }
1618            tag_value.unwrap_or_else(|| Cow::Borrowed(variant.effective_name()))
1619        } else {
1620            Cow::Borrowed(variant.effective_name())
1621        };
1622
1623        // Check if the format wants to handle this with tag syntax
1624        let use_tag_syntax = self
1625            .serializer
1626            .write_variant_tag(&tag_name)
1627            .map_err(SerializeError::Backend)?;
1628
1629        self.push(PathSegment::Variant(Cow::Owned(tag_name.to_string())));
1630
1631        let result = if use_tag_syntax {
1632            self.serialize_variant_after_tag(enum_, variant)
1633        } else {
1634            self.serialize_standard_externally_tagged(enum_, variant)
1635        };
1636
1637        self.pop();
1638        result
1639    }
1640
1641    fn serialize_variant_after_tag<'mem, 'facet>(
1642        &mut self,
1643        enum_: facet_reflect::PeekEnum<'mem, 'facet>,
1644        variant: &'static facet_core::Variant,
1645    ) -> Result<(), SerializeError<S::Error>> {
1646        let field_mode = self.serializer.struct_field_mode();
1647
1648        match variant.data.kind {
1649            StructKind::Unit => {
1650                self.serializer
1651                    .finish_variant_tag_unit_payload()
1652                    .map_err(SerializeError::Backend)?;
1653                Ok(())
1654            }
1655            StructKind::TupleStruct | StructKind::Tuple => {
1656                let field_count = variant.data.fields.len();
1657                if field_count == 1 {
1658                    let inner = enum_
1659                        .field(0)
1660                        .map_err(|_| {
1661                            SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
1662                        })?
1663                        .ok_or(SerializeError::Internal(Cow::Borrowed(
1664                            "variant reported 1 field but field(0) returned None",
1665                        )))?;
1666                    if let Some(field_def) = variant.data.fields.first().copied()
1667                        && let Some(proxy_def) =
1668                            field_def.effective_proxy(self.serializer.format_namespace())
1669                    {
1670                        self.with_field_context(Some(field_def), |this| {
1671                            this.serialize_via_proxy(inner, proxy_def)
1672                        })?;
1673                    } else {
1674                        self.with_field_context(variant.data.fields.first().copied(), |this| {
1675                            this.serialize_impl(inner)
1676                        })?;
1677                    }
1678                } else {
1679                    self.serializer
1680                        .begin_seq_after_tag()
1681                        .map_err(SerializeError::Backend)?;
1682                    for idx in 0..field_count {
1683                        let inner = enum_
1684                            .field(idx)
1685                            .map_err(|_| {
1686                                SerializeError::Internal(Cow::Borrowed(
1687                                    "variant field lookup failed",
1688                                ))
1689                            })?
1690                            .ok_or(SerializeError::Internal(Cow::Borrowed(
1691                                "variant field missing while iterating tuple fields",
1692                            )))?;
1693                        self.push(PathSegment::Index(idx));
1694                        if let Some(field_def) = variant.data.fields.get(idx).copied()
1695                            && let Some(proxy_def) =
1696                                field_def.effective_proxy(self.serializer.format_namespace())
1697                        {
1698                            self.with_field_context(Some(field_def), |this| {
1699                                this.serialize_via_proxy(inner, proxy_def)
1700                            })?;
1701                        } else {
1702                            self.with_field_context(
1703                                variant.data.fields.get(idx).copied(),
1704                                |this| this.serialize_impl(inner),
1705                            )?;
1706                        }
1707                        self.pop();
1708                    }
1709                    self.serializer.end_seq().map_err(SerializeError::Backend)?;
1710                }
1711                Ok(())
1712            }
1713            StructKind::Struct => {
1714                let is_other = variant.is_other();
1715                let fields_iter: alloc::boxed::Box<
1716                    dyn Iterator<Item = (facet_reflect::FieldItem, facet_reflect::Peek<'_, '_>)>,
1717                > = if field_mode == StructFieldMode::Unnamed {
1718                    alloc::boxed::Box::new(enum_.fields_for_binary_serialize())
1719                } else {
1720                    alloc::boxed::Box::new(enum_.fields_for_serialize())
1721                };
1722                let mut fields: alloc::vec::Vec<_> = fields_iter
1723                    .filter(|(field_item, _)| {
1724                        if is_other {
1725                            field_item
1726                                .field
1727                                .map(|f| f.metadata_kind().is_none() && !f.is_variant_tag())
1728                                .unwrap_or(true)
1729                        } else {
1730                            true
1731                        }
1732                    })
1733                    .collect();
1734
1735                if fields.is_empty() {
1736                    self.serializer
1737                        .finish_variant_tag_unit_payload()
1738                        .map_err(SerializeError::Backend)?;
1739                    return Ok(());
1740                }
1741
1742                self.serializer
1743                    .begin_struct_after_tag()
1744                    .map_err(SerializeError::Backend)?;
1745                sort_fields_if_needed(self.serializer, &mut fields);
1746                for (field_item, field_value) in fields {
1747                    self.serializer
1748                        .field_metadata(&field_item)
1749                        .map_err(SerializeError::Backend)?;
1750                    if field_mode == StructFieldMode::Named {
1751                        self.serializer
1752                            .field_key(field_item.effective_name())
1753                            .map_err(SerializeError::Backend)?;
1754                    }
1755                    self.push(PathSegment::Field(Cow::Owned(
1756                        field_item.effective_name().to_string(),
1757                    )));
1758                    self.serialize_field_value(&field_item, field_value)?;
1759                    self.pop();
1760                }
1761                self.serializer
1762                    .end_struct()
1763                    .map_err(SerializeError::Backend)?;
1764                Ok(())
1765            }
1766        }
1767    }
1768
1769    fn serialize_standard_externally_tagged<'mem, 'facet>(
1770        &mut self,
1771        enum_: facet_reflect::PeekEnum<'mem, 'facet>,
1772        variant: &'static facet_core::Variant,
1773    ) -> Result<(), SerializeError<S::Error>> {
1774        let field_mode = self.serializer.struct_field_mode();
1775
1776        match variant.data.kind {
1777            StructKind::Unit => {
1778                self.serializer
1779                    .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
1780                    .map_err(SerializeError::Backend)?;
1781                Ok(())
1782            }
1783            StructKind::TupleStruct | StructKind::Tuple => {
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                let field_count = variant.data.fields.len();
1792                if field_count == 1 {
1793                    let inner = enum_
1794                        .field(0)
1795                        .map_err(|_| {
1796                            SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
1797                        })?
1798                        .ok_or(SerializeError::Internal(Cow::Borrowed(
1799                            "variant reported 1 field but field(0) returned None",
1800                        )))?;
1801                    if let Some(field_def) = variant.data.fields.first().copied()
1802                        && let Some(proxy_def) =
1803                            field_def.effective_proxy(self.serializer.format_namespace())
1804                    {
1805                        self.with_field_context(Some(field_def), |this| {
1806                            this.serialize_via_proxy(inner, proxy_def)
1807                        })?;
1808                    } else {
1809                        self.with_field_context(variant.data.fields.first().copied(), |this| {
1810                            this.serialize_impl(inner)
1811                        })?;
1812                    }
1813                } else {
1814                    self.serializer
1815                        .begin_seq()
1816                        .map_err(SerializeError::Backend)?;
1817                    for idx in 0..field_count {
1818                        let inner = enum_
1819                            .field(idx)
1820                            .map_err(|_| {
1821                                SerializeError::Internal(Cow::Borrowed(
1822                                    "variant field lookup failed",
1823                                ))
1824                            })?
1825                            .ok_or(SerializeError::Internal(Cow::Borrowed(
1826                                "variant field missing while iterating tuple fields",
1827                            )))?;
1828                        self.push(PathSegment::Index(idx));
1829                        if let Some(field_def) = variant.data.fields.get(idx).copied()
1830                            && let Some(proxy_def) =
1831                                field_def.effective_proxy(self.serializer.format_namespace())
1832                        {
1833                            self.with_field_context(Some(field_def), |this| {
1834                                this.serialize_via_proxy(inner, proxy_def)
1835                            })?;
1836                        } else {
1837                            self.with_field_context(
1838                                variant.data.fields.get(idx).copied(),
1839                                |this| this.serialize_impl(inner),
1840                            )?;
1841                        }
1842                        self.pop();
1843                    }
1844                    self.serializer.end_seq().map_err(SerializeError::Backend)?;
1845                }
1846
1847                self.serializer
1848                    .end_struct()
1849                    .map_err(SerializeError::Backend)?;
1850                Ok(())
1851            }
1852            StructKind::Struct => {
1853                self.serializer
1854                    .begin_struct()
1855                    .map_err(SerializeError::Backend)?;
1856                self.serializer
1857                    .field_key(variant.effective_name())
1858                    .map_err(SerializeError::Backend)?;
1859
1860                self.serializer
1861                    .begin_struct()
1862                    .map_err(SerializeError::Backend)?;
1863                let mut fields: alloc::vec::Vec<_> = if field_mode == StructFieldMode::Unnamed {
1864                    enum_.fields_for_binary_serialize().collect()
1865                } else {
1866                    enum_.fields_for_serialize().collect()
1867                };
1868                sort_fields_if_needed(self.serializer, &mut fields);
1869                for (field_item, field_value) in fields {
1870                    self.serializer
1871                        .field_metadata(&field_item)
1872                        .map_err(SerializeError::Backend)?;
1873                    if field_mode == StructFieldMode::Named {
1874                        self.serializer
1875                            .field_key(field_item.effective_name())
1876                            .map_err(SerializeError::Backend)?;
1877                    }
1878                    self.push(PathSegment::Field(Cow::Owned(
1879                        field_item.effective_name().to_string(),
1880                    )));
1881                    self.serialize_field_value(&field_item, field_value)?;
1882                    self.pop();
1883                }
1884                self.serializer
1885                    .end_struct()
1886                    .map_err(SerializeError::Backend)?;
1887
1888                self.serializer
1889                    .end_struct()
1890                    .map_err(SerializeError::Backend)?;
1891                Ok(())
1892            }
1893        }
1894    }
1895
1896    fn serialize_untagged_enum<'mem, 'facet>(
1897        &mut self,
1898        enum_: facet_reflect::PeekEnum<'mem, 'facet>,
1899        variant: &'static facet_core::Variant,
1900    ) -> Result<(), SerializeError<S::Error>> {
1901        let field_mode = self.serializer.struct_field_mode();
1902
1903        match variant.data.kind {
1904            StructKind::Unit => self
1905                .serializer
1906                .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
1907                .map_err(SerializeError::Backend),
1908            StructKind::TupleStruct | StructKind::Tuple => {
1909                let field_count = variant.data.fields.len();
1910                if field_count == 1 {
1911                    let inner = enum_
1912                        .field(0)
1913                        .map_err(|_| {
1914                            SerializeError::Internal(Cow::Borrowed("variant field lookup failed"))
1915                        })?
1916                        .ok_or(SerializeError::Internal(Cow::Borrowed(
1917                            "variant reported 1 field but field(0) returned None",
1918                        )))?;
1919                    let field_def = variant.data.fields.first().copied();
1920                    self.with_field_context(field_def, |this| this.serialize_impl(inner))
1921                } else {
1922                    self.serializer
1923                        .begin_seq()
1924                        .map_err(SerializeError::Backend)?;
1925                    for idx in 0..field_count {
1926                        let inner = enum_
1927                            .field(idx)
1928                            .map_err(|_| {
1929                                SerializeError::Internal(Cow::Borrowed(
1930                                    "variant field lookup failed",
1931                                ))
1932                            })?
1933                            .ok_or(SerializeError::Internal(Cow::Borrowed(
1934                                "variant field missing while iterating tuple fields",
1935                            )))?;
1936                        self.push(PathSegment::Index(idx));
1937                        let field_def = variant.data.fields.get(idx).copied();
1938                        self.with_field_context(field_def, |this| this.serialize_impl(inner))?;
1939                        self.pop();
1940                    }
1941                    self.serializer.end_seq().map_err(SerializeError::Backend)?;
1942                    Ok(())
1943                }
1944            }
1945            StructKind::Struct => {
1946                self.serializer
1947                    .begin_struct()
1948                    .map_err(SerializeError::Backend)?;
1949                let mut fields: alloc::vec::Vec<_> = if field_mode == StructFieldMode::Unnamed {
1950                    enum_.fields_for_binary_serialize().collect()
1951                } else {
1952                    enum_.fields_for_serialize().collect()
1953                };
1954                sort_fields_if_needed(self.serializer, &mut fields);
1955                for (field_item, field_value) in fields {
1956                    self.serializer
1957                        .field_metadata(&field_item)
1958                        .map_err(SerializeError::Backend)?;
1959                    if field_mode == StructFieldMode::Named {
1960                        self.serializer
1961                            .field_key(field_item.effective_name())
1962                            .map_err(SerializeError::Backend)?;
1963                    }
1964                    self.push(PathSegment::Field(Cow::Owned(
1965                        field_item.effective_name().to_string(),
1966                    )));
1967                    self.serialize_field_value(&field_item, field_value)?;
1968                    self.pop();
1969                }
1970                self.serializer
1971                    .end_struct()
1972                    .map_err(SerializeError::Backend)?;
1973                Ok(())
1974            }
1975        }
1976    }
1977
1978    fn serialize_dynamic_value<'mem, 'facet>(
1979        &mut self,
1980        dynamic: facet_reflect::PeekDynamicValue<'mem, 'facet>,
1981    ) -> Result<(), SerializeError<S::Error>> {
1982        let tagged = self.serializer.dynamic_value_encoding() == DynamicValueEncoding::Tagged;
1983
1984        match dynamic.kind() {
1985            DynValueKind::Null => {
1986                if tagged {
1987                    self.serializer
1988                        .dynamic_value_tag(DynamicValueTag::Null)
1989                        .map_err(SerializeError::Backend)?;
1990                }
1991                self.serializer
1992                    .scalar(ScalarValue::Null)
1993                    .map_err(SerializeError::Backend)
1994            }
1995            DynValueKind::Bool => {
1996                let value = dynamic.as_bool().ok_or_else(|| {
1997                    SerializeError::Internal(Cow::Borrowed("dynamic bool missing value"))
1998                })?;
1999                if tagged {
2000                    self.serializer
2001                        .dynamic_value_tag(DynamicValueTag::Bool)
2002                        .map_err(SerializeError::Backend)?;
2003                }
2004                self.serializer
2005                    .scalar(ScalarValue::Bool(value))
2006                    .map_err(SerializeError::Backend)
2007            }
2008            DynValueKind::Number => {
2009                if let Some(n) = dynamic.as_i64() {
2010                    if tagged {
2011                        self.serializer
2012                            .dynamic_value_tag(DynamicValueTag::I64)
2013                            .map_err(SerializeError::Backend)?;
2014                    }
2015                    self.serializer
2016                        .scalar(ScalarValue::I64(n))
2017                        .map_err(SerializeError::Backend)
2018                } else if let Some(n) = dynamic.as_u64() {
2019                    if tagged {
2020                        self.serializer
2021                            .dynamic_value_tag(DynamicValueTag::U64)
2022                            .map_err(SerializeError::Backend)?;
2023                    }
2024                    self.serializer
2025                        .scalar(ScalarValue::U64(n))
2026                        .map_err(SerializeError::Backend)
2027                } else if let Some(n) = dynamic.as_f64() {
2028                    if tagged {
2029                        self.serializer
2030                            .dynamic_value_tag(DynamicValueTag::F64)
2031                            .map_err(SerializeError::Backend)?;
2032                    }
2033                    self.serializer
2034                        .scalar(ScalarValue::F64(n))
2035                        .map_err(SerializeError::Backend)
2036                } else {
2037                    Err(SerializeError::Unsupported(Cow::Borrowed(
2038                        "dynamic number not representable",
2039                    )))
2040                }
2041            }
2042            DynValueKind::String => {
2043                let value = dynamic.as_str().ok_or_else(|| {
2044                    SerializeError::Internal(Cow::Borrowed("dynamic string missing value"))
2045                })?;
2046                if tagged {
2047                    self.serializer
2048                        .dynamic_value_tag(DynamicValueTag::String)
2049                        .map_err(SerializeError::Backend)?;
2050                }
2051                self.serializer
2052                    .scalar(ScalarValue::Str(Cow::Borrowed(value)))
2053                    .map_err(SerializeError::Backend)
2054            }
2055            DynValueKind::Bytes => {
2056                let value = dynamic.as_bytes().ok_or_else(|| {
2057                    SerializeError::Internal(Cow::Borrowed("dynamic bytes missing value"))
2058                })?;
2059                if tagged {
2060                    self.serializer
2061                        .dynamic_value_tag(DynamicValueTag::Bytes)
2062                        .map_err(SerializeError::Backend)?;
2063                }
2064                self.serializer
2065                    .scalar(ScalarValue::Bytes(Cow::Borrowed(value)))
2066                    .map_err(SerializeError::Backend)
2067            }
2068            DynValueKind::Array => {
2069                let len = dynamic.array_len().ok_or_else(|| {
2070                    SerializeError::Internal(Cow::Borrowed("dynamic array missing length"))
2071                })?;
2072                if tagged {
2073                    self.serializer
2074                        .dynamic_value_tag(DynamicValueTag::Array)
2075                        .map_err(SerializeError::Backend)?;
2076                }
2077                self.serializer
2078                    .begin_seq_with_len(len)
2079                    .map_err(SerializeError::Backend)?;
2080                if let Some(iter) = dynamic.array_iter() {
2081                    for (idx, item) in iter.enumerate() {
2082                        self.push(PathSegment::Index(idx));
2083                        self.serialize_impl(item)?;
2084                        self.pop();
2085                    }
2086                }
2087                self.serializer.end_seq().map_err(SerializeError::Backend)
2088            }
2089            DynValueKind::Object => {
2090                let len = dynamic.object_len().ok_or_else(|| {
2091                    SerializeError::Internal(Cow::Borrowed("dynamic object missing length"))
2092                })?;
2093                if tagged {
2094                    self.serializer
2095                        .dynamic_value_tag(DynamicValueTag::Object)
2096                        .map_err(SerializeError::Backend)?;
2097                }
2098                match self.serializer.map_encoding() {
2099                    MapEncoding::Pairs => {
2100                        self.serializer
2101                            .begin_map_with_len(len)
2102                            .map_err(SerializeError::Backend)?;
2103                        if let Some(iter) = dynamic.object_iter() {
2104                            for (key, value) in iter {
2105                                self.serializer
2106                                    .scalar(ScalarValue::Str(Cow::Borrowed(key)))
2107                                    .map_err(SerializeError::Backend)?;
2108                                self.push(PathSegment::Field(Cow::Owned(key.to_string())));
2109                                self.serialize_impl(value)?;
2110                                self.pop();
2111                            }
2112                        }
2113                        self.serializer.end_map().map_err(SerializeError::Backend)
2114                    }
2115                    MapEncoding::Struct => {
2116                        self.serializer
2117                            .begin_struct()
2118                            .map_err(SerializeError::Backend)?;
2119                        if let Some(iter) = dynamic.object_iter() {
2120                            for (key, value) in iter {
2121                                self.serializer
2122                                    .field_key(key)
2123                                    .map_err(SerializeError::Backend)?;
2124                                self.push(PathSegment::Field(Cow::Owned(key.to_string())));
2125                                self.serialize_impl(value)?;
2126                                self.pop();
2127                            }
2128                        }
2129                        self.serializer
2130                            .end_struct()
2131                            .map_err(SerializeError::Backend)
2132                    }
2133                }
2134            }
2135            DynValueKind::DateTime => {
2136                let dt = dynamic.as_datetime().ok_or_else(|| {
2137                    SerializeError::Internal(Cow::Borrowed("dynamic datetime missing value"))
2138                })?;
2139                if tagged {
2140                    self.serializer
2141                        .dynamic_value_tag(DynamicValueTag::DateTime)
2142                        .map_err(SerializeError::Backend)?;
2143                }
2144                let s = format_dyn_datetime(dt);
2145                self.serializer
2146                    .scalar(ScalarValue::Str(Cow::Owned(s)))
2147                    .map_err(SerializeError::Backend)
2148            }
2149            DynValueKind::QName | DynValueKind::Uuid => Err(SerializeError::Unsupported(
2150                Cow::Borrowed("dynamic QName/Uuid serialization is not supported"),
2151            )),
2152        }
2153    }
2154
2155    #[allow(unsafe_code)]
2156    fn serialize_via_proxy<'mem, 'facet>(
2157        &mut self,
2158        value: Peek<'mem, 'facet>,
2159        proxy_def: &'static facet_core::ProxyDef,
2160    ) -> Result<(), SerializeError<S::Error>> {
2161        let proxy_shape = proxy_def.shape;
2162        let proxy_layout = proxy_shape.layout.sized_layout().map_err(|_| {
2163            SerializeError::Unsupported(Cow::Borrowed("proxy type must be sized for serialization"))
2164        })?;
2165
2166        let proxy_uninit = facet_core::alloc_for_layout(proxy_layout);
2167        let convert_result = unsafe { (proxy_def.convert_out)(value.data(), proxy_uninit) };
2168
2169        let proxy_ptr = match convert_result {
2170            Ok(ptr) => ptr,
2171            Err(msg) => {
2172                unsafe { facet_core::dealloc_for_layout(proxy_uninit.assume_init(), proxy_layout) };
2173                return Err(SerializeError::Unsupported(Cow::Owned(msg)));
2174            }
2175        };
2176
2177        let proxy_peek = unsafe { Peek::unchecked_new(proxy_ptr.as_const(), proxy_shape) };
2178        let result = self.serialize_impl(proxy_peek);
2179
2180        unsafe {
2181            let _ = proxy_shape.call_drop_in_place(proxy_ptr);
2182            facet_core::dealloc_for_layout(proxy_ptr, proxy_layout);
2183        }
2184
2185        result
2186    }
2187}
2188
2189impl<E: Debug> std::error::Error for SerializeError<E> {}
2190
2191/// Get a human-readable name for a Def variant.
2192fn def_kind_name(def: &Def) -> &'static str {
2193    match def {
2194        Def::Undefined => "Undefined",
2195        Def::Scalar => "Scalar",
2196        Def::Map(_) => "Map",
2197        Def::Set(_) => "Set",
2198        Def::List(_) => "List",
2199        Def::Array(_) => "Array",
2200        Def::NdArray(_) => "NdArray",
2201        Def::Slice(_) => "Slice",
2202        Def::Option(_) => "Option",
2203        Def::Result(_) => "Result",
2204        Def::DynamicValue(_) => "DynamicValue",
2205        Def::Pointer(_) => "Pointer",
2206        _ => "Unknown",
2207    }
2208}
2209
2210/// Serialize a root value using the shared traversal logic.
2211pub fn serialize_root<'mem, 'facet, S>(
2212    serializer: &mut S,
2213    value: Peek<'mem, 'facet>,
2214) -> Result<(), SerializeError<S::Error>>
2215where
2216    S: FormatSerializer,
2217{
2218    let mut ctx = SerializeContext::new(serializer);
2219    ctx.serialize(value)
2220}
2221
2222/// Helper to sort fields according to format preference (currently a no-op).
2223fn sort_fields_if_needed<'mem, 'facet, S>(
2224    _serializer: &S,
2225    _fields: &mut alloc::vec::Vec<(facet_reflect::FieldItem, Peek<'mem, 'facet>)>,
2226) where
2227    S: FormatSerializer,
2228{
2229    // Currently only Declaration order is supported, which preserves the original order.
2230}
2231
2232fn format_dyn_datetime(
2233    (year, month, day, hour, minute, second, nanos, kind): (
2234        i32,
2235        u8,
2236        u8,
2237        u8,
2238        u8,
2239        u8,
2240        u32,
2241        DynDateTimeKind,
2242    ),
2243) -> String {
2244    let mut out = String::new();
2245    match kind {
2246        DynDateTimeKind::Offset { offset_minutes } => {
2247            let _ = write!(
2248                out,
2249                "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
2250                year, month, day, hour, minute, second
2251            );
2252            if nanos > 0 {
2253                let _ = write!(out, ".{:09}", nanos);
2254            }
2255            if offset_minutes == 0 {
2256                out.push('Z');
2257            } else {
2258                let sign = if offset_minutes >= 0 { '+' } else { '-' };
2259                let abs = offset_minutes.unsigned_abs();
2260                let _ = write!(out, "{}{:02}:{:02}", sign, abs / 60, abs % 60);
2261            }
2262        }
2263        DynDateTimeKind::LocalDateTime => {
2264            let _ = write!(
2265                out,
2266                "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}",
2267                year, month, day, hour, minute, second
2268            );
2269            if nanos > 0 {
2270                let _ = write!(out, ".{:09}", nanos);
2271            }
2272        }
2273        DynDateTimeKind::LocalDate => {
2274            let _ = write!(out, "{:04}-{:02}-{:02}", year, month, day);
2275        }
2276        DynDateTimeKind::LocalTime => {
2277            let _ = write!(out, "{:02}:{:02}:{:02}", hour, minute, second);
2278            if nanos > 0 {
2279                let _ = write!(out, ".{:09}", nanos);
2280            }
2281        }
2282    }
2283    out
2284}
2285
2286fn serialize_numeric_enum<S>(
2287    serializer: &mut S,
2288    variant: &'static facet_core::Variant,
2289) -> Result<(), SerializeError<S::Error>>
2290where
2291    S: FormatSerializer,
2292{
2293    let discriminant = variant
2294        .discriminant
2295        .ok_or(SerializeError::Unsupported(Cow::Borrowed(
2296            "Enum without a discriminant",
2297        )))?;
2298    serializer
2299        .scalar(ScalarValue::I64(discriminant))
2300        .map_err(SerializeError::Backend)
2301}
2302
2303/// Dereference a pointer/reference (Box, Arc, etc.) to get the underlying value
2304fn deref_if_pointer<'mem, 'facet>(peek: Peek<'mem, 'facet>) -> Peek<'mem, 'facet> {
2305    if let Ok(ptr) = peek.into_pointer()
2306        && let Some(target) = ptr.borrow_inner()
2307    {
2308        return deref_if_pointer(target);
2309    }
2310    peek
2311}
2312
2313// ─────────────────────────────────────────────────────────────────────────────
2314// Shape-guided serialization of dynamic values
2315// ─────────────────────────────────────────────────────────────────────────────
2316
2317/// Serialize a dynamic value (like `facet_value::Value`) according to a target shape.
2318///
2319/// This is the inverse of `FormatDeserializer::deserialize_with_shape`. It allows serializing
2320/// a `Value` as if it were a typed value matching the shape, without the dynamic value's
2321/// type discriminants.
2322///
2323/// This is useful for non-self-describing formats like postcard where you want to:
2324/// 1. Parse JSON into a `Value`
2325/// 2. Serialize it to postcard bytes matching a typed schema
2326///
2327/// # Arguments
2328///
2329/// * `serializer` - The format serializer to use
2330/// * `value` - A `Peek` into a dynamic value type (like `facet_value::Value`)
2331/// * `target_shape` - The shape describing the expected wire format
2332///
2333/// # Errors
2334///
2335/// Returns an error if:
2336/// - The value is not a dynamic value type
2337/// - The value's structure doesn't match the target shape
2338pub fn serialize_value_with_shape<S>(
2339    serializer: &mut S,
2340    value: Peek<'_, '_>,
2341    target_shape: &'static Shape,
2342) -> Result<(), SerializeError<S::Error>>
2343where
2344    S: FormatSerializer,
2345{
2346    let dynamic = value.into_dynamic_value().map_err(|_| {
2347        SerializeError::Unsupported(Cow::Borrowed(
2348            "serialize_value_with_shape requires a DynamicValue type",
2349        ))
2350    })?;
2351
2352    serialize_dynamic_with_shape(serializer, dynamic, target_shape, value.shape())
2353}
2354
2355fn serialize_dynamic_with_shape<S>(
2356    serializer: &mut S,
2357    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2358    target_shape: &'static Shape,
2359    value_shape: &'static Shape,
2360) -> Result<(), SerializeError<S::Error>>
2361where
2362    S: FormatSerializer,
2363{
2364    use facet_core::{ListDef, OptionDef, ScalarType as CoreScalarType, Type, UserType};
2365
2366    // Handle smart pointers - unwrap to the inner shape
2367    if let Def::Pointer(ptr_def) = target_shape.def
2368        && let Some(pointee) = ptr_def.pointee
2369    {
2370        return serialize_dynamic_with_shape(serializer, dynamic, pointee, value_shape);
2371    }
2372
2373    // Handle transparent wrappers via .inner
2374    if let Some(inner_shape) = target_shape.inner {
2375        // Skip collection types that have .inner for variance but aren't transparent wrappers
2376        if !matches!(
2377            target_shape.def,
2378            Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
2379        ) {
2380            return serialize_dynamic_with_shape(serializer, dynamic, inner_shape, value_shape);
2381        }
2382    }
2383
2384    // Handle Option<T>
2385    if let Def::Option(OptionDef { t: inner_shape, .. }) = target_shape.def {
2386        return serialize_option_from_dynamic(serializer, dynamic, inner_shape, value_shape);
2387    }
2388
2389    // Handle List/Vec
2390    if let Def::List(ListDef { t: item_shape, .. }) = target_shape.def {
2391        return serialize_list_from_dynamic(serializer, dynamic, item_shape, value_shape);
2392    }
2393
2394    // Handle Array [T; N]
2395    if let Def::Array(array_def) = target_shape.def {
2396        return serialize_array_from_dynamic(serializer, dynamic, array_def.t, value_shape);
2397    }
2398
2399    // Handle Map
2400    if let Def::Map(map_def) = target_shape.def {
2401        return serialize_map_from_dynamic(serializer, dynamic, map_def.k, map_def.v, value_shape);
2402    }
2403
2404    // Handle scalars
2405    if let Some(scalar_type) = CoreScalarType::try_from_shape(target_shape) {
2406        return serialize_scalar_from_dynamic(serializer, dynamic, scalar_type);
2407    }
2408
2409    // Handle structs and enums by Type
2410    match target_shape.ty {
2411        Type::User(UserType::Struct(struct_def)) => {
2412            serialize_struct_from_dynamic(serializer, dynamic, struct_def, value_shape)
2413        }
2414        Type::User(UserType::Enum(enum_def)) => {
2415            serialize_enum_from_dynamic(serializer, dynamic, enum_def, target_shape, value_shape)
2416        }
2417        _ => Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2418            "unsupported target shape for serialize_value_with_shape: {}",
2419            target_shape
2420        )))),
2421    }
2422}
2423
2424fn serialize_option_from_dynamic<S>(
2425    serializer: &mut S,
2426    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2427    inner_shape: &'static Shape,
2428    value_shape: &'static Shape,
2429) -> Result<(), SerializeError<S::Error>>
2430where
2431    S: FormatSerializer,
2432{
2433    if dynamic.kind() == DynValueKind::Null {
2434        serializer.serialize_none().map_err(SerializeError::Backend)
2435    } else {
2436        serializer
2437            .begin_option_some()
2438            .map_err(SerializeError::Backend)?;
2439        serialize_dynamic_with_shape(serializer, dynamic, inner_shape, value_shape)
2440    }
2441}
2442
2443fn serialize_list_from_dynamic<S>(
2444    serializer: &mut S,
2445    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2446    item_shape: &'static Shape,
2447    value_shape: &'static Shape,
2448) -> Result<(), SerializeError<S::Error>>
2449where
2450    S: FormatSerializer,
2451{
2452    let len = dynamic.array_len().ok_or_else(|| {
2453        SerializeError::Unsupported(Cow::Borrowed(
2454            "expected array value for list/vec target shape",
2455        ))
2456    })?;
2457
2458    serializer
2459        .begin_seq_with_len(len)
2460        .map_err(SerializeError::Backend)?;
2461
2462    if let Some(iter) = dynamic.array_iter() {
2463        for elem in iter {
2464            let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2465                SerializeError::Internal(Cow::Borrowed("array element is not a dynamic value"))
2466            })?;
2467            serialize_dynamic_with_shape(serializer, elem_dyn, item_shape, value_shape)?;
2468        }
2469    }
2470
2471    serializer.end_seq().map_err(SerializeError::Backend)
2472}
2473
2474fn serialize_array_from_dynamic<S>(
2475    serializer: &mut S,
2476    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2477    item_shape: &'static Shape,
2478    value_shape: &'static Shape,
2479) -> Result<(), SerializeError<S::Error>>
2480where
2481    S: FormatSerializer,
2482{
2483    // Arrays don't have length prefix in postcard
2484    serializer.begin_seq().map_err(SerializeError::Backend)?;
2485
2486    if let Some(iter) = dynamic.array_iter() {
2487        for elem in iter {
2488            let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2489                SerializeError::Internal(Cow::Borrowed("array element is not a dynamic value"))
2490            })?;
2491            serialize_dynamic_with_shape(serializer, elem_dyn, item_shape, value_shape)?;
2492        }
2493    }
2494
2495    serializer.end_seq().map_err(SerializeError::Backend)
2496}
2497
2498fn serialize_map_from_dynamic<S>(
2499    serializer: &mut S,
2500    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2501    key_shape: &'static Shape,
2502    value_shape_inner: &'static Shape,
2503    value_shape: &'static Shape,
2504) -> Result<(), SerializeError<S::Error>>
2505where
2506    S: FormatSerializer,
2507{
2508    let len = dynamic.object_len().ok_or_else(|| {
2509        SerializeError::Unsupported(Cow::Borrowed("expected object value for map target shape"))
2510    })?;
2511
2512    match serializer.map_encoding() {
2513        MapEncoding::Pairs => {
2514            serializer
2515                .begin_map_with_len(len)
2516                .map_err(SerializeError::Backend)?;
2517
2518            if let Some(iter) = dynamic.object_iter() {
2519                for (key, val) in iter {
2520                    // Serialize key according to key_shape
2521                    serialize_string_as_scalar(serializer, key, key_shape)?;
2522                    // Serialize value
2523                    let val_dyn = val.into_dynamic_value().map_err(|_| {
2524                        SerializeError::Internal(Cow::Borrowed(
2525                            "object value is not a dynamic value",
2526                        ))
2527                    })?;
2528                    serialize_dynamic_with_shape(
2529                        serializer,
2530                        val_dyn,
2531                        value_shape_inner,
2532                        value_shape,
2533                    )?;
2534                }
2535            }
2536
2537            serializer.end_map().map_err(SerializeError::Backend)
2538        }
2539        MapEncoding::Struct => {
2540            serializer.begin_struct().map_err(SerializeError::Backend)?;
2541
2542            if let Some(iter) = dynamic.object_iter() {
2543                for (key, val) in iter {
2544                    serializer.field_key(key).map_err(SerializeError::Backend)?;
2545                    let val_dyn = val.into_dynamic_value().map_err(|_| {
2546                        SerializeError::Internal(Cow::Borrowed(
2547                            "object value is not a dynamic value",
2548                        ))
2549                    })?;
2550                    serialize_dynamic_with_shape(
2551                        serializer,
2552                        val_dyn,
2553                        value_shape_inner,
2554                        value_shape,
2555                    )?;
2556                }
2557            }
2558
2559            serializer.end_struct().map_err(SerializeError::Backend)
2560        }
2561    }
2562}
2563
2564fn serialize_string_as_scalar<S>(
2565    serializer: &mut S,
2566    s: &str,
2567    _key_shape: &'static Shape,
2568) -> Result<(), SerializeError<S::Error>>
2569where
2570    S: FormatSerializer,
2571{
2572    // For now, serialize string keys directly
2573    // TODO: Handle non-string key types if needed
2574    serializer
2575        .scalar(ScalarValue::Str(Cow::Borrowed(s)))
2576        .map_err(SerializeError::Backend)
2577}
2578
2579fn serialize_scalar_from_dynamic<S>(
2580    serializer: &mut S,
2581    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2582    scalar_type: facet_core::ScalarType,
2583) -> Result<(), SerializeError<S::Error>>
2584where
2585    S: FormatSerializer,
2586{
2587    use facet_core::ScalarType as ST;
2588
2589    match scalar_type {
2590        ST::Unit => serializer
2591            .scalar(ScalarValue::Null)
2592            .map_err(SerializeError::Backend),
2593        ST::Bool => {
2594            let v = dynamic
2595                .as_bool()
2596                .ok_or_else(|| SerializeError::Unsupported(Cow::Borrowed("expected bool value")))?;
2597            serializer
2598                .scalar(ScalarValue::Bool(v))
2599                .map_err(SerializeError::Backend)
2600        }
2601        ST::Char => {
2602            let s = dynamic.as_str().ok_or_else(|| {
2603                SerializeError::Unsupported(Cow::Borrowed("expected string value for char"))
2604            })?;
2605            let c = s.chars().next().ok_or_else(|| {
2606                SerializeError::Unsupported(Cow::Borrowed("expected non-empty string for char"))
2607            })?;
2608            serializer
2609                .scalar(ScalarValue::Char(c))
2610                .map_err(SerializeError::Backend)
2611        }
2612        ST::Str | ST::String | ST::CowStr => {
2613            let s = dynamic.as_str().ok_or_else(|| {
2614                SerializeError::Unsupported(Cow::Borrowed("expected string value"))
2615            })?;
2616            serializer
2617                .scalar(ScalarValue::Str(Cow::Borrowed(s)))
2618                .map_err(SerializeError::Backend)
2619        }
2620        ST::U8 | ST::U16 | ST::U32 | ST::U64 | ST::USize => {
2621            let n = dynamic.as_u64().ok_or_else(|| {
2622                SerializeError::Unsupported(Cow::Borrowed("expected unsigned integer value"))
2623            })?;
2624            serializer
2625                .scalar(ScalarValue::U64(n))
2626                .map_err(SerializeError::Backend)
2627        }
2628        ST::U128 => {
2629            let n = dynamic.as_u64().ok_or_else(|| {
2630                SerializeError::Unsupported(Cow::Borrowed("expected unsigned integer value"))
2631            })?;
2632            serializer
2633                .scalar(ScalarValue::U128(n as u128))
2634                .map_err(SerializeError::Backend)
2635        }
2636        ST::I8 | ST::I16 | ST::I32 | ST::I64 | ST::ISize => {
2637            let n = dynamic.as_i64().ok_or_else(|| {
2638                SerializeError::Unsupported(Cow::Borrowed("expected signed integer value"))
2639            })?;
2640            serializer
2641                .scalar(ScalarValue::I64(n))
2642                .map_err(SerializeError::Backend)
2643        }
2644        ST::I128 => {
2645            let n = dynamic.as_i64().ok_or_else(|| {
2646                SerializeError::Unsupported(Cow::Borrowed("expected signed integer value"))
2647            })?;
2648            serializer
2649                .scalar(ScalarValue::I128(n as i128))
2650                .map_err(SerializeError::Backend)
2651        }
2652        ST::F32 | ST::F64 => {
2653            let n = dynamic.as_f64().ok_or_else(|| {
2654                SerializeError::Unsupported(Cow::Borrowed("expected float value"))
2655            })?;
2656            serializer
2657                .scalar(ScalarValue::F64(n))
2658                .map_err(SerializeError::Backend)
2659        }
2660        _ => Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2661            "unsupported scalar type: {:?}",
2662            scalar_type
2663        )))),
2664    }
2665}
2666
2667fn serialize_struct_from_dynamic<S>(
2668    serializer: &mut S,
2669    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2670    struct_def: facet_core::StructType,
2671    value_shape: &'static Shape,
2672) -> Result<(), SerializeError<S::Error>>
2673where
2674    S: FormatSerializer,
2675{
2676    let is_tuple = matches!(struct_def.kind, StructKind::Tuple | StructKind::TupleStruct);
2677
2678    if is_tuple {
2679        // For tuples, expect an array value
2680        serializer.begin_seq().map_err(SerializeError::Backend)?;
2681
2682        let iter = dynamic.array_iter().ok_or_else(|| {
2683            SerializeError::Unsupported(Cow::Borrowed("expected array value for tuple"))
2684        })?;
2685
2686        for (field, elem) in struct_def.fields.iter().zip(iter) {
2687            let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2688                SerializeError::Internal(Cow::Borrowed("tuple element is not a dynamic value"))
2689            })?;
2690            serialize_dynamic_with_shape(serializer, elem_dyn, field.shape(), value_shape)?;
2691        }
2692
2693        serializer.end_seq().map_err(SerializeError::Backend)
2694    } else {
2695        // For named structs, expect an object value
2696        let field_mode = serializer.struct_field_mode();
2697
2698        serializer.begin_struct().map_err(SerializeError::Backend)?;
2699
2700        for field in struct_def.fields {
2701            // Skip metadata fields
2702            if field.is_metadata() {
2703                continue;
2704            }
2705
2706            let field_name = field.name;
2707            let field_value = dynamic.object_get(field_name).ok_or_else(|| {
2708                SerializeError::Unsupported(Cow::Owned(alloc::format!(
2709                    "missing field '{}' in object",
2710                    field_name
2711                )))
2712            })?;
2713
2714            if field_mode == StructFieldMode::Named {
2715                serializer
2716                    .field_key(field_name)
2717                    .map_err(SerializeError::Backend)?;
2718            }
2719
2720            let field_dyn = field_value.into_dynamic_value().map_err(|_| {
2721                SerializeError::Internal(Cow::Borrowed("field value is not a dynamic value"))
2722            })?;
2723            serialize_dynamic_with_shape(serializer, field_dyn, field.shape(), value_shape)?;
2724        }
2725
2726        serializer.end_struct().map_err(SerializeError::Backend)
2727    }
2728}
2729
2730fn serialize_enum_from_dynamic<S>(
2731    serializer: &mut S,
2732    dynamic: facet_reflect::PeekDynamicValue<'_, '_>,
2733    enum_def: facet_core::EnumType,
2734    target_shape: &'static Shape,
2735    value_shape: &'static Shape,
2736) -> Result<(), SerializeError<S::Error>>
2737where
2738    S: FormatSerializer,
2739{
2740    // For index-based encoding (postcard), we need to:
2741    // 1. Determine the variant from the Value
2742    // 2. Emit the variant index
2743    // 3. Serialize the variant's payload
2744
2745    let use_index = serializer.enum_variant_encoding() == EnumVariantEncoding::Index;
2746
2747    match dynamic.kind() {
2748        // Unit variant represented as a string
2749        DynValueKind::String => {
2750            let variant_name = dynamic.as_str().ok_or_else(|| {
2751                SerializeError::Internal(Cow::Borrowed("expected string for unit variant"))
2752            })?;
2753
2754            let (variant_index, variant) = enum_def
2755                .variants
2756                .iter()
2757                .enumerate()
2758                .find(|(_, v)| v.effective_name() == variant_name)
2759                .ok_or_else(|| {
2760                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2761                        "unknown variant '{}'",
2762                        variant_name
2763                    )))
2764                })?;
2765
2766            if use_index {
2767                serializer
2768                    .begin_enum_variant(variant_index, variant.effective_name())
2769                    .map_err(SerializeError::Backend)?;
2770                // Unit variant has no payload
2771                Ok(())
2772            } else {
2773                serializer
2774                    .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
2775                    .map_err(SerializeError::Backend)
2776            }
2777        }
2778
2779        // Variant with payload represented as object { "VariantName": payload }
2780        DynValueKind::Object => {
2781            // For externally tagged enums, the object has a single key = variant name
2782            let obj_len = dynamic.object_len().unwrap_or(0);
2783            if obj_len != 1 {
2784                return Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2785                    "expected single-key object for enum variant, got {} keys",
2786                    obj_len
2787                ))));
2788            }
2789
2790            let (variant_name, payload) = dynamic.object_get_entry(0).ok_or_else(|| {
2791                SerializeError::Internal(Cow::Borrowed("expected object entry for enum variant"))
2792            })?;
2793
2794            let (variant_index, variant) = enum_def
2795                .variants
2796                .iter()
2797                .enumerate()
2798                .find(|(_, v)| v.effective_name() == variant_name)
2799                .ok_or_else(|| {
2800                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2801                        "unknown variant '{}'",
2802                        variant_name
2803                    )))
2804                })?;
2805
2806            let payload_dyn = payload.into_dynamic_value().map_err(|_| {
2807                SerializeError::Internal(Cow::Borrowed("variant payload is not a dynamic value"))
2808            })?;
2809
2810            if use_index {
2811                serializer
2812                    .begin_enum_variant(variant_index, variant.effective_name())
2813                    .map_err(SerializeError::Backend)?;
2814
2815                // Serialize payload based on variant kind
2816                match variant.data.kind {
2817                    StructKind::Unit => {
2818                        // No payload to serialize
2819                    }
2820                    StructKind::TupleStruct | StructKind::Tuple => {
2821                        if variant.data.fields.len() == 1 {
2822                            // Newtype variant - serialize the single field directly
2823                            serialize_dynamic_with_shape(
2824                                serializer,
2825                                payload_dyn,
2826                                variant.data.fields[0].shape(),
2827                                value_shape,
2828                            )?;
2829                        } else {
2830                            // Multi-field tuple variant - expect array
2831                            let iter = payload_dyn.array_iter().ok_or_else(|| {
2832                                SerializeError::Unsupported(Cow::Borrowed(
2833                                    "expected array for tuple variant payload",
2834                                ))
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                                        "tuple 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                        }
2851                    }
2852                    StructKind::Struct => {
2853                        // Struct variant - expect object
2854                        for field in variant.data.fields {
2855                            let field_value =
2856                                payload_dyn.object_get(field.name).ok_or_else(|| {
2857                                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2858                                        "missing field '{}' in struct variant",
2859                                        field.name
2860                                    )))
2861                                })?;
2862                            let field_dyn = field_value.into_dynamic_value().map_err(|_| {
2863                                SerializeError::Internal(Cow::Borrowed(
2864                                    "field value is not a dynamic value",
2865                                ))
2866                            })?;
2867                            serialize_dynamic_with_shape(
2868                                serializer,
2869                                field_dyn,
2870                                field.shape(),
2871                                value_shape,
2872                            )?;
2873                        }
2874                    }
2875                }
2876
2877                Ok(())
2878            } else {
2879                // Externally tagged representation
2880                serializer.begin_struct().map_err(SerializeError::Backend)?;
2881                serializer
2882                    .field_key(variant.effective_name())
2883                    .map_err(SerializeError::Backend)?;
2884
2885                match variant.data.kind {
2886                    StructKind::Unit => {
2887                        serializer
2888                            .scalar(ScalarValue::Null)
2889                            .map_err(SerializeError::Backend)?;
2890                    }
2891                    StructKind::TupleStruct | StructKind::Tuple => {
2892                        if variant.data.fields.len() == 1 {
2893                            serialize_dynamic_with_shape(
2894                                serializer,
2895                                payload_dyn,
2896                                variant.data.fields[0].shape(),
2897                                value_shape,
2898                            )?;
2899                        } else {
2900                            serializer.begin_seq().map_err(SerializeError::Backend)?;
2901                            let iter = payload_dyn.array_iter().ok_or_else(|| {
2902                                SerializeError::Unsupported(Cow::Borrowed(
2903                                    "expected array for tuple variant",
2904                                ))
2905                            })?;
2906                            for (field, elem) in variant.data.fields.iter().zip(iter) {
2907                                let elem_dyn = elem.into_dynamic_value().map_err(|_| {
2908                                    SerializeError::Internal(Cow::Borrowed(
2909                                        "element is not a dynamic value",
2910                                    ))
2911                                })?;
2912                                serialize_dynamic_with_shape(
2913                                    serializer,
2914                                    elem_dyn,
2915                                    field.shape(),
2916                                    value_shape,
2917                                )?;
2918                            }
2919                            serializer.end_seq().map_err(SerializeError::Backend)?;
2920                        }
2921                    }
2922                    StructKind::Struct => {
2923                        serializer.begin_struct().map_err(SerializeError::Backend)?;
2924                        for field in variant.data.fields {
2925                            let field_value =
2926                                payload_dyn.object_get(field.name).ok_or_else(|| {
2927                                    SerializeError::Unsupported(Cow::Owned(alloc::format!(
2928                                        "missing field '{}'",
2929                                        field.name
2930                                    )))
2931                                })?;
2932                            serializer
2933                                .field_key(field.name)
2934                                .map_err(SerializeError::Backend)?;
2935                            let field_dyn = field_value.into_dynamic_value().map_err(|_| {
2936                                SerializeError::Internal(Cow::Borrowed(
2937                                    "field is not a dynamic value",
2938                                ))
2939                            })?;
2940                            serialize_dynamic_with_shape(
2941                                serializer,
2942                                field_dyn,
2943                                field.shape(),
2944                                value_shape,
2945                            )?;
2946                        }
2947                        serializer.end_struct().map_err(SerializeError::Backend)?;
2948                    }
2949                }
2950
2951                serializer.end_struct().map_err(SerializeError::Backend)
2952            }
2953        }
2954
2955        // Null could be a unit variant named "Null" (untagged representation)
2956        DynValueKind::Null => {
2957            // Check if there's a Null variant or fallback for Option-like enums
2958            // Note: we match against the Rust name (v.name) since these are well-known Rust identifiers
2959            if let Some((variant_index, variant)) = enum_def
2960                .variants
2961                .iter()
2962                .enumerate()
2963                .find(|(_, v)| v.name.eq_ignore_ascii_case("null") || v.name == "None")
2964            {
2965                if use_index {
2966                    serializer
2967                        .begin_enum_variant(variant_index, variant.effective_name())
2968                        .map_err(SerializeError::Backend)?;
2969                    Ok(())
2970                } else {
2971                    serializer
2972                        .scalar(ScalarValue::Str(Cow::Borrowed(variant.effective_name())))
2973                        .map_err(SerializeError::Backend)
2974                }
2975            } else {
2976                Err(SerializeError::Unsupported(Cow::Borrowed(
2977                    "null value for enum without null/None variant",
2978                )))
2979            }
2980        }
2981
2982        _ => {
2983            // For untagged enums, we might need to try matching variants
2984            // This is a simplified implementation - could be extended
2985            let _ = target_shape; // Suppress unused warning
2986            Err(SerializeError::Unsupported(Cow::Owned(alloc::format!(
2987                "unsupported dynamic value kind {:?} for enum serialization",
2988                dynamic.kind()
2989            ))))
2990        }
2991    }
2992}