Skip to main content

facet_format/
serializer.rs

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