Skip to main content

facet_format/
serializer.rs

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