Skip to main content

facet_format/
serializer.rs

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