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