Skip to main content

facet_format/deserializer/
entry.rs

1use std::borrow::Cow;
2
3use facet_core::{Def, OpaqueDeserialize, ScalarType, Shape, StructKind, Type, UserType};
4use facet_reflect::{DeserStrategy, Partial, ReflectErrorKind, Span};
5
6use crate::{
7    ContainerKind, DeserializeError, DeserializeErrorKind, FieldEvidence, FieldLocationHint,
8    FormatDeserializer, ParseEventKind, ScalarTypeHint, ScalarValue, SpanGuard, ValueMeta,
9};
10
11/// Specifies where metadata should come from during deserialization.
12#[derive(Debug, Clone, Default)]
13#[non_exhaustive]
14pub enum MetaSource<'a> {
15    /// Use explicit metadata from an outer context (borrowed).
16    ///
17    /// Use cases:
18    /// - **Consumed a VariantTag**: We consumed `@tag` before a value and need to pass
19    ///   the tag name (and doc if present) to the inner value so metadata containers
20    ///   can capture it.
21    /// - **Recursive through wrappers**: Going through proxies, transparent converts,
22    ///   pointers, `begin_inner` - same logical value, pass through same metadata.
23    /// - **Merged metadata**: When we've built up metadata from multiple sources
24    ///   (e.g., tag span + value span combined) and need to pass the merged result.
25    Explicit(&'a ValueMeta<'a>),
26
27    /// Use explicit metadata that was constructed locally (owned).
28    ///
29    /// Use cases:
30    /// - **Struct field with attached metadata**: The field key had doc comments or
31    ///   other metadata that should apply to the field value.
32    Owned(ValueMeta<'a>),
33
34    /// Get fresh metadata from the events being parsed.
35    ///
36    /// Use this when deserializing a new value that has no pre-consumed context:
37    /// list items, map keys/values, struct fields without special metadata, etc.
38    #[default]
39    FromEvents,
40}
41
42impl<'a> From<&'a ValueMeta<'a>> for MetaSource<'a> {
43    fn from(meta: &'a ValueMeta<'a>) -> Self {
44        MetaSource::Explicit(meta)
45    }
46}
47
48impl<'a> From<ValueMeta<'a>> for MetaSource<'a> {
49    fn from(meta: ValueMeta<'a>) -> Self {
50        MetaSource::Owned(meta)
51    }
52}
53
54impl<'parser, 'input, const BORROW: bool> FormatDeserializer<'parser, 'input, BORROW> {
55    /// Main deserialization entry point - deserialize into a Partial.
56    ///
57    /// Uses the precomputed `DeserStrategy` from TypePlan for fast dispatch.
58    /// The strategy is computed once at Partial allocation time, eliminating
59    /// repeated runtime inspection of Shape/Def/vtable during deserialization.
60    ///
61    /// The `meta` parameter specifies where metadata should come from:
62    /// - `MetaSource::Explicit(meta)` - use provided metadata from outer context
63    /// - `MetaSource::FromEvents` - read fresh metadata from the events being parsed
64    #[inline(never)]
65    pub fn deserialize_into(
66        &mut self,
67        wip: Partial<'input, BORROW>,
68        meta: MetaSource<'input>,
69    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
70        self.deserialize_into_inner(wip, meta)
71    }
72
73    #[inline(never)]
74    pub(crate) fn deserialize_into_inner(
75        &mut self,
76        wip: Partial<'input, BORROW>,
77        meta: MetaSource<'input>,
78    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
79        let _guard = SpanGuard::new(self.last_span);
80        let shape = wip.shape();
81        trace!(
82            shape_name = %shape,
83            "deserialize_into: starting"
84        );
85
86        // === SPECIAL CASES (cannot be precomputed) ===
87
88        // Check for raw capture type (e.g., RawJson) - parser-specific
89        if self.parser.raw_capture_shape() == Some(shape) {
90            let Some(raw) = self.capture_raw()? else {
91                return Err(DeserializeErrorKind::RawCaptureNotSupported { shape }
92                    .with_span(self.last_span));
93            };
94            let raw_cow = if BORROW {
95                Cow::Borrowed(raw)
96            } else {
97                Cow::Owned(raw.to_owned())
98            };
99            return Ok(wip
100                .begin_nth_field(0)?
101                .with(|w| self.set_string_value(w, raw_cow))?
102                .end()?);
103        }
104
105        // Check for builder_shape (immutable collections like Bytes -> BytesMut)
106        // This MUST be checked at runtime because begin_inner() transitions to the
107        // builder shape but keeps the same TypePlan node. If we used a precomputed
108        // strategy, we'd get infinite recursion (BytesMut would still have Builder strategy).
109        if shape.builder_shape.is_some() {
110            return Ok(wip
111                .begin_inner()?
112                .with(|w| self.deserialize_into(w, meta))?
113                .end()?);
114        }
115
116        // === STRATEGY-BASED DISPATCH ===
117        // All other cases use precomputed DeserStrategy for O(1) dispatch.
118        // Use the precomputed DeserStrategy for O(1) dispatch
119
120        let strategy = wip.deser_strategy();
121        trace!(?strategy, "deserialize_into: using precomputed strategy");
122
123        match strategy {
124            Some(DeserStrategy::ContainerProxy) => self.deserialize_container_proxy(wip, meta),
125
126            Some(DeserStrategy::FieldProxy) => self.deserialize_field_proxy(wip, meta),
127
128            Some(DeserStrategy::Pointer { .. }) => {
129                trace!("deserialize_into: dispatching to deserialize_pointer");
130                self.deserialize_pointer(wip, meta)
131            }
132
133            Some(DeserStrategy::TransparentConvert { .. }) => {
134                trace!("deserialize_into: dispatching via begin_inner (transparent convert)");
135                self.deserialize_transparent_convert(wip, meta)
136            }
137
138            Some(DeserStrategy::Scalar {
139                scalar_type,
140                is_from_str,
141            }) => {
142                let scalar_type = *scalar_type; // Copy before moving wip
143                let is_from_str = *is_from_str;
144                trace!("deserialize_into: dispatching to deserialize_scalar");
145                self.deserialize_scalar(wip, scalar_type, is_from_str)
146            }
147
148            Some(DeserStrategy::Struct) => {
149                trace!("deserialize_into: dispatching to deserialize_struct");
150                self.deserialize_struct(wip)
151            }
152
153            Some(DeserStrategy::Tuple {
154                field_count,
155                is_single_field_transparent,
156            }) => {
157                let field_count = *field_count;
158                let is_single_field_transparent = *is_single_field_transparent;
159                trace!("deserialize_into: dispatching to deserialize_tuple");
160                self.deserialize_tuple(wip, field_count, is_single_field_transparent)
161            }
162
163            Some(DeserStrategy::Enum) => {
164                trace!("deserialize_into: dispatching to deserialize_enum");
165                self.deserialize_enum(wip)
166            }
167
168            Some(DeserStrategy::Option { .. }) => {
169                trace!("deserialize_into: dispatching to deserialize_option");
170                self.deserialize_option(wip)
171            }
172
173            Some(DeserStrategy::Result { .. }) => {
174                trace!("deserialize_into: dispatching to deserialize_result_as_enum");
175                self.deserialize_result_as_enum(wip)
176            }
177
178            Some(DeserStrategy::List { is_byte_vec, .. }) => {
179                let is_byte_vec = *is_byte_vec;
180                trace!("deserialize_into: dispatching to deserialize_list");
181                self.deserialize_list(wip, is_byte_vec)
182            }
183
184            Some(DeserStrategy::Map { .. }) => {
185                trace!("deserialize_into: dispatching to deserialize_map");
186                self.deserialize_map(wip)
187            }
188
189            Some(DeserStrategy::Set { .. }) => {
190                trace!("deserialize_into: dispatching to deserialize_set");
191                self.deserialize_set(wip)
192            }
193
194            Some(DeserStrategy::Array { .. }) => {
195                trace!("deserialize_into: dispatching to deserialize_array");
196                self.deserialize_array(wip)
197            }
198
199            Some(DeserStrategy::DynamicValue) => {
200                trace!("deserialize_into: dispatching to deserialize_dynamic_value");
201                self.deserialize_dynamic_value(wip)
202            }
203
204            Some(DeserStrategy::MetadataContainer) => {
205                trace!("deserialize_into: dispatching to deserialize_metadata_container");
206                self.deserialize_metadata_container(wip, meta)
207            }
208
209            Some(DeserStrategy::BackRef { .. }) => {
210                // BackRef is automatically resolved by deser_strategy() - this branch
211                // should never be reached. If it is, something is wrong with TypePlan.
212                unreachable!("deser_strategy() should resolve BackRef to target strategy")
213            }
214
215            Some(DeserStrategy::Opaque) => self.deserialize_opaque(wip),
216
217            Some(DeserStrategy::OpaquePointer) => self.unsupported_opaque_pointer(shape),
218
219            // A deserialization strategy variant added since this match was written.
220            Some(_) => self.unsupported_strategy(shape),
221
222            None => self.missing_strategy(shape),
223        }
224    }
225
226    #[inline(never)]
227    fn deserialize_container_proxy(
228        &mut self,
229        wip: Partial<'input, BORROW>,
230        meta: MetaSource<'input>,
231    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
232        let format_ns = self.parser.format_namespace();
233        let (wip, _) = wip.begin_custom_deserialization_from_shape_with_format(format_ns)?;
234        Ok(wip.with(|w| self.deserialize_into(w, meta))?.end()?)
235    }
236
237    #[inline(never)]
238    fn deserialize_field_proxy(
239        &mut self,
240        wip: Partial<'input, BORROW>,
241        meta: MetaSource<'input>,
242    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
243        let format_ns = self.parser.format_namespace();
244        let wip = wip.begin_custom_deserialization_with_format(format_ns)?;
245        Ok(wip.with(|w| self.deserialize_into(w, meta))?.end()?)
246    }
247
248    #[inline(never)]
249    fn deserialize_transparent_convert(
250        &mut self,
251        wip: Partial<'input, BORROW>,
252        meta: MetaSource<'input>,
253    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
254        Ok(wip
255            .begin_inner()?
256            .with(|w| self.deserialize_into(w, meta))?
257            .end()?)
258    }
259
260    #[inline(never)]
261    fn deserialize_opaque(
262        &mut self,
263        wip: Partial<'input, BORROW>,
264    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
265        let shape = wip.shape();
266        let Some(adapter) = shape.opaque_adapter else {
267            return Err(DeserializeErrorKind::Unsupported {
268                message: format!(
269                    "cannot deserialize opaque type {} - add a proxy or opaque adapter",
270                    shape
271                )
272                .into(),
273            }
274            .with_span(self.last_span));
275        };
276
277        let trailing_opaque = wip
278            .nearest_field()
279            .is_some_and(|f| f.has_builtin_attr("trailing"));
280
281        if self.is_non_self_describing() {
282            let handled = if trailing_opaque {
283                self.parser.hint_remaining_byte_sequence()
284            } else {
285                self.parser.hint_byte_sequence()
286            };
287            if !handled {
288                self.parser.hint_scalar_type(ScalarTypeHint::Bytes);
289            }
290        }
291
292        let expected = if trailing_opaque {
293            "remaining bytes for trailing opaque adapter"
294        } else {
295            "bytes for opaque adapter"
296        };
297        let event = self.expect_event(expected)?;
298        let input = match event.kind {
299            ParseEventKind::Scalar(ScalarValue::Bytes(bytes)) => {
300                if BORROW {
301                    match bytes {
302                        Cow::Borrowed(b) => OpaqueDeserialize::Borrowed(b),
303                        Cow::Owned(v) => OpaqueDeserialize::Owned(v),
304                    }
305                } else {
306                    OpaqueDeserialize::Owned(bytes.into_owned())
307                }
308            }
309            _ => {
310                return Err(self.mk_err(
311                    &wip,
312                    DeserializeErrorKind::UnexpectedToken {
313                        expected,
314                        got: event.kind_name().into(),
315                    },
316                ));
317            }
318        };
319
320        let adapter = *adapter;
321        #[allow(unsafe_code)]
322        let wip = unsafe {
323            wip.set_from_function(move |target| match (adapter.deserialize)(input, target) {
324                Ok(_) => Ok(()),
325                Err(message) => Err(ReflectErrorKind::OperationFailedOwned {
326                    shape,
327                    operation: format!("opaque adapter deserialize failed: {message}"),
328                }),
329            })?
330        };
331        Ok(wip)
332    }
333
334    #[inline(never)]
335    fn unsupported_opaque_pointer(
336        &self,
337        shape: &'static Shape,
338    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
339        Err(DeserializeErrorKind::Unsupported {
340            message: format!(
341                "cannot deserialize opaque type {} - add a proxy to make it deserializable",
342                shape
343            )
344            .into(),
345        }
346        .with_span(self.last_span))
347    }
348
349    #[inline(never)]
350    fn unsupported_strategy(
351        &self,
352        shape: &'static Shape,
353    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
354        Err(DeserializeErrorKind::Unsupported {
355            message: format!("unsupported deserialization strategy for {:?}", shape.def).into(),
356        }
357        .with_span(self.last_span))
358    }
359
360    #[inline(never)]
361    fn missing_strategy(
362        &self,
363        shape: &'static Shape,
364    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
365        Err(DeserializeErrorKind::Unsupported {
366            message: format!(
367                "missing deserialization strategy for shape: {:?} (TypePlan bug)",
368                shape.def
369            )
370            .into(),
371        }
372        .with_span(self.last_span))
373    }
374
375    /// Deserialize a metadata container (like `Spanned<T>`, `Documented<T>`).
376    ///
377    /// These require special handling - the value field gets the data,
378    /// metadata fields are populated from the passed `meta`.
379    ///
380    /// VariantTag events (like `@tag"hello"` in Styx) are already consumed by
381    /// `deserialize_into` and passed down via `meta`.
382    fn deserialize_metadata_container(
383        &mut self,
384        mut wip: Partial<'input, BORROW>,
385        meta: MetaSource<'input>,
386    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
387        // Check if this metadata container has a "tag" metadata field.
388        // Only consume VariantTag events if the container can store them.
389        // Otherwise, the VariantTag belongs to the inner value (e.g., an enum).
390        let has_tag_field = if let Type::User(UserType::Struct(st)) = &wip.shape().ty {
391            st.fields.iter().any(|f| f.metadata_kind() == Some("tag"))
392        } else {
393            false
394        };
395
396        // Check for VariantTag at the start - this handles tagged values like `@tag"hello"`.
397        // We consume it here and merge it into meta, but ONLY if this container has a tag field.
398        let event = self.expect_peek("value for metadata container")?;
399        let (meta_owned, tag_span) =
400            if has_tag_field && let ParseEventKind::VariantTag(tag) = &event.kind {
401                let tag_span = event.span;
402                let tag = tag.map(Cow::Borrowed);
403                let _ = self.expect_event("variant tag")?; // consume it
404
405                // Merge tag with any existing meta (preserving doc comments)
406                let mut builder = ValueMeta::builder().span(tag_span);
407                let existing_meta = match &meta {
408                    MetaSource::Explicit(m) => Some(*m),
409                    MetaSource::Owned(m) => Some(m),
410                    MetaSource::FromEvents => None,
411                };
412                if let Some(existing) = existing_meta
413                    && let Some(doc) = existing.doc()
414                {
415                    builder = builder.doc(doc.to_vec());
416                }
417                if let Some(tag) = tag {
418                    builder = builder.tag(tag);
419                }
420                (Some(builder.build()), Some(tag_span))
421            } else {
422                (None, None)
423            };
424
425        // Resolve meta: use constructed meta from VariantTag, or explicit meta, or empty
426        static EMPTY_META: ValueMeta<'static> = ValueMeta::empty();
427        let meta: &ValueMeta<'_> = match (&meta_owned, &meta) {
428            (Some(owned), _) => owned,
429            (None, MetaSource::Explicit(explicit)) => explicit,
430            (None, MetaSource::Owned(owned)) => owned,
431            (None, MetaSource::FromEvents) => &EMPTY_META,
432        };
433
434        let shape = wip.shape();
435        trace!(%shape, "deserialize_into: metadata container detected");
436
437        // Deserialize the value field and track its span
438        let mut value_span = Span::default();
439        if let Type::User(UserType::Struct(st)) = &shape.ty {
440            for field in st.fields {
441                if field.metadata_kind().is_none() {
442                    // This is the value field - recurse into it (fresh metadata from events)
443                    wip = wip
444                        .begin_field(field.effective_name())?
445                        .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
446                        .end()?;
447                    value_span = self.last_span;
448                    break;
449                }
450            }
451        }
452
453        // Compute the full span: if we have a tag span, extend from tag start to value end.
454        // Otherwise, just use the value's span.
455        let full_span = if let Some(tag_span) = tag_span {
456            Span {
457                offset: tag_span.offset,
458                len: (value_span.offset + value_span.len).saturating_sub(tag_span.offset),
459            }
460        } else {
461            value_span
462        };
463
464        // Populate metadata fields
465        if let Type::User(UserType::Struct(st)) = &shape.ty {
466            for field in st.fields {
467                if let Some(kind) = field.metadata_kind() {
468                    wip = wip.begin_field(field.effective_name())?;
469                    wip = self.populate_metadata_field_with_span(wip, kind, meta, full_span)?;
470                    wip = wip.end()?;
471                }
472            }
473        }
474        Ok(wip)
475    }
476
477    /// Populate a single metadata field on a metadata container.
478    fn populate_metadata_field(
479        &mut self,
480        wip: Partial<'input, BORROW>,
481        kind: &str,
482        meta: &ValueMeta<'input>,
483    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
484        self.populate_metadata_field_with_span(wip, kind, meta, self.last_span)
485    }
486
487    /// Populate a single metadata field on a metadata container with an explicit span.
488    fn populate_metadata_field_with_span(
489        &mut self,
490        mut wip: Partial<'input, BORROW>,
491        kind: &str,
492        meta: &ValueMeta<'input>,
493        span: Span,
494    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
495        match kind {
496            "span" => {
497                // Check if the field is Option<Span> or just Span
498                let is_option = matches!(wip.shape().def, Def::Option(_));
499                if is_option {
500                    wip = wip.begin_some()?;
501                }
502                wip = wip
503                    .begin_field("offset")?
504                    .set(span.offset)?
505                    .end()?
506                    .begin_field("len")?
507                    .set(span.len)?
508                    .end()?;
509                if is_option {
510                    wip = wip.end()?;
511                }
512            }
513            "doc" => {
514                if let Some(doc_lines) = meta.doc() {
515                    // Set as Some(Vec<String>)
516                    wip = wip.begin_some()?.init_list()?;
517                    for line in doc_lines {
518                        wip = wip
519                            .begin_list_item()?
520                            .with(|w| self.set_string_value(w, line.clone()))?
521                            .end()?;
522                    }
523                    wip = wip.end()?;
524                } else {
525                    wip = wip.set_default()?;
526                }
527            }
528            "tag" => {
529                if let Some(tag_name) = meta.tag() {
530                    wip = wip
531                        .begin_some()?
532                        .with(|w| self.set_string_value(w, tag_name.clone()))?
533                        .end()?;
534                } else {
535                    wip = wip.set_default()?;
536                }
537            }
538            _ => {
539                // Unknown metadata kind - set to default
540                wip = wip.set_default()?;
541            }
542        }
543        Ok(wip)
544    }
545
546    /// Deserialize using an explicit source shape for parser hints.
547    ///
548    /// This walks `hint_shape` for control flow and parser hints, but builds
549    /// into the `wip` Partial (which should be a DynamicValue like `Value`).
550    pub fn deserialize_into_with_shape(
551        &mut self,
552        wip: Partial<'input, BORROW>,
553        hint_shape: &'static Shape,
554    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
555        self.deserialize_value_recursive(wip, hint_shape)
556    }
557
558    /// Internal recursive deserialization using hint_shape for dispatch.
559    pub(crate) fn deserialize_value_recursive(
560        &mut self,
561        mut wip: Partial<'input, BORROW>,
562        hint_shape: &'static Shape,
563    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
564        // Handle Option
565        if let Def::Option(opt_def) = &hint_shape.def {
566            if self.is_non_self_describing() {
567                self.parser.hint_option();
568            }
569            let event = self.expect_peek("value for option")?;
570            // Treat both Null and Unit as None
571            // Unit is used by Styx for tags without payload (e.g., @string vs @string{...})
572            if matches!(
573                event.kind,
574                ParseEventKind::Scalar(ScalarValue::Null | ScalarValue::Unit)
575            ) {
576                let _ = self.expect_event("null or unit")?;
577                wip = wip.set_default()?;
578            } else {
579                wip = self.deserialize_value_recursive(wip, opt_def.t)?;
580            }
581            return Ok(wip);
582        }
583
584        // Handle smart pointers - unwrap to inner type
585        if let Def::Pointer(ptr_def) = &hint_shape.def
586            && let Some(pointee) = ptr_def.pointee()
587        {
588            return self.deserialize_value_recursive(wip, pointee);
589        }
590
591        // Handle transparent wrappers (but not collections)
592        if let Some(inner) = hint_shape.inner
593            && !matches!(
594                &hint_shape.def,
595                Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
596            )
597        {
598            return self.deserialize_value_recursive(wip, inner);
599        }
600
601        // Dispatch based on hint shape type
602        match &hint_shape.ty {
603            Type::User(UserType::Struct(struct_def)) => {
604                if matches!(struct_def.kind, StructKind::Tuple | StructKind::TupleStruct) {
605                    self.deserialize_tuple_dynamic(wip, struct_def.fields)
606                } else {
607                    self.deserialize_struct_dynamic(wip, struct_def.fields)
608                }
609            }
610            Type::User(UserType::Enum(enum_def)) => self.deserialize_enum_dynamic(wip, enum_def),
611            _ => match &hint_shape.def {
612                Def::Scalar => self.deserialize_scalar_dynamic(wip, hint_shape),
613                Def::List(list_def) => self.deserialize_list_dynamic(wip, list_def.t),
614                Def::Array(array_def) => {
615                    self.deserialize_array_dynamic(wip, array_def.t, array_def.n)
616                }
617                Def::Map(map_def) => self.deserialize_map_dynamic(wip, map_def.k, map_def.v),
618                Def::Set(set_def) => self.deserialize_list_dynamic(wip, set_def.t),
619                _ => Err(DeserializeErrorKind::Unsupported {
620                    message: format!(
621                        "unsupported hint shape for dynamic deserialization: {:?}",
622                        hint_shape.def
623                    )
624                    .into(),
625                }
626                .with_span(self.last_span)),
627            },
628        }
629    }
630
631    pub(crate) fn deserialize_option(
632        &mut self,
633        mut wip: Partial<'input, BORROW>,
634    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
635        let _guard = SpanGuard::new(self.last_span);
636
637        // Hint to non-self-describing parsers that an Option is expected
638        if self.is_non_self_describing() {
639            self.parser.hint_option();
640        }
641
642        let event = self.expect_peek("value for option")?;
643
644        // Treat both Null and Unit as None
645        // Unit is used by Styx for tags without payload (e.g., @string vs @string{...})
646        if matches!(
647            event.kind,
648            ParseEventKind::Scalar(ScalarValue::Null | ScalarValue::Unit)
649        ) {
650            // Consume the null/unit
651            let _ = self.expect_event("null or unit")?;
652            // Set to None (default)
653            wip = wip.set_default()?;
654        } else {
655            // Some(value)
656            wip = wip
657                .begin_some()?
658                .with(|w| self.deserialize_into_inner(w, MetaSource::FromEvents))?
659                .end()?;
660        }
661        Ok(wip)
662    }
663
664    pub(crate) fn deserialize_struct(
665        &mut self,
666        wip: Partial<'input, BORROW>,
667    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
668        let struct_plan = wip.struct_plan().unwrap();
669        if struct_plan.has_flatten {
670            self.deserialize_struct_with_flatten(wip)
671        } else {
672            self.deserialize_struct_simple(wip)
673        }
674    }
675
676    pub(crate) fn deserialize_tuple(
677        &mut self,
678        mut wip: Partial<'input, BORROW>,
679        field_count: usize,
680        is_single_field_transparent: bool,
681    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
682        let _guard = SpanGuard::new(self.last_span);
683
684        // Special case: transparent newtypes (marked with #[facet(transparent)] or
685        // #[repr(transparent)]) can accept values directly without a sequence wrapper.
686        // This enables patterns like:
687        //   #[facet(transparent)]
688        //   struct Wrapper(i32);
689        //   toml: "value = 42"  ->  Wrapper(42)
690        // Plain tuple structs without the transparent attribute use array syntax.
691        //
692        // IMPORTANT: This check must come BEFORE hint_struct_fields() because transparent
693        // newtypes don't consume struct events - they deserialize the inner value directly.
694        // If we hint struct fields first, non-self-describing parsers will expect to emit
695        // StructStart, causing "unexpected token: got struct start" errors.
696        if is_single_field_transparent {
697            // Unwrap into field 0 and deserialize directly
698            return Ok(wip
699                .begin_nth_field(0)?
700                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
701                .end()?);
702        }
703
704        // Hint to non-self-describing parsers how many fields to expect
705        // Tuples are like positional structs, so we use hint_struct_fields
706        if self.is_non_self_describing() {
707            self.parser.hint_struct_fields(field_count);
708        }
709
710        // Special case: unit type () can accept Scalar(Unit) or Scalar(Null) directly
711        // This enables patterns like styx bare identifiers: { id, name } -> IndexMap<String, ()>
712        // and JSON null values for unit types (e.g., ConfigValue::Null(Spanned<()>))
713        if field_count == 0 {
714            let peeked = self.expect_peek("value")?;
715            if matches!(
716                peeked.kind,
717                ParseEventKind::Scalar(ScalarValue::Unit | ScalarValue::Null)
718            ) {
719                self.expect_event("value")?; // consume the unit/null scalar
720                return Ok(wip);
721            }
722        }
723
724        let event = self.expect_event("value")?;
725
726        // Accept either SequenceStart (JSON arrays) or StructStart (for
727        // non-self-describing formats like postcard where tuples are positional structs)
728        let struct_mode = match event.kind {
729            ParseEventKind::SequenceStart(_) => false,
730            // For non-self-describing formats, StructStart(Object) is valid for tuples
731            // because hint_struct_fields was called and tuples are positional structs
732            ParseEventKind::StructStart(_) if !self.parser.is_self_describing() => true,
733            // For self-describing formats like TOML/JSON, objects with numeric keys
734            // (e.g., { "0" = true, "1" = 1 }) are valid tuple representations
735            ParseEventKind::StructStart(ContainerKind::Object) => true,
736            ParseEventKind::StructStart(kind) => {
737                return Err(DeserializeError {
738                    span: Some(self.last_span),
739                    path: Some(wip.path()),
740                    kind: DeserializeErrorKind::UnexpectedToken {
741                        expected: "array",
742                        got: kind.name().into(),
743                    },
744                });
745            }
746            _ => {
747                return Err(DeserializeError {
748                    span: Some(self.last_span),
749                    path: Some(wip.path()),
750                    kind: DeserializeErrorKind::UnexpectedToken {
751                        expected: "sequence start for tuple",
752                        got: event.kind_name().into(),
753                    },
754                });
755            }
756        };
757
758        let mut index = 0usize;
759        loop {
760            let event = self.expect_peek("value")?;
761
762            // Check for end of container
763            if matches!(
764                event.kind,
765                ParseEventKind::SequenceEnd | ParseEventKind::StructEnd
766            ) {
767                self.expect_event("value")?;
768                break;
769            }
770
771            // In struct mode, skip FieldKey events
772            if struct_mode && matches!(event.kind, ParseEventKind::FieldKey(_)) {
773                self.expect_event("value")?;
774                continue;
775            }
776
777            // Select field by index
778            wip = wip
779                .begin_nth_field(index)?
780                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
781                .end()?;
782            index += 1;
783        }
784
785        Ok(wip)
786    }
787
788    /// Helper to collect field evidence using save/restore.
789    ///
790    /// This saves the deserializer state (parser position AND event buffer),
791    /// reads through the current struct to collect field names and their scalar
792    /// values, then restores the state.
793    pub(crate) fn collect_evidence(
794        &mut self,
795    ) -> Result<Vec<FieldEvidence<'input>>, DeserializeError> {
796        let save_point = self.save();
797
798        let mut evidence = Vec::new();
799        let mut depth = 0i32;
800        let mut pending_field_name: Option<Cow<'input, str>> = None;
801
802        // Read through the structure
803        while let Ok(event) = self.expect_event("evidence") {
804            match event.kind {
805                ParseEventKind::StructStart(_) => {
806                    depth += 1;
807                    // If we were expecting a value, record field with no scalar
808                    if depth > 1
809                        && let Some(name) = pending_field_name.take()
810                    {
811                        evidence.push(FieldEvidence {
812                            name,
813                            location: FieldLocationHint::KeyValue,
814                            value_type: None,
815                            scalar_value: None,
816                        });
817                    }
818                }
819                ParseEventKind::StructEnd => {
820                    depth -= 1;
821                    if depth == 0 {
822                        break;
823                    }
824                }
825                ParseEventKind::SequenceStart(_) => {
826                    depth += 1;
827                    // If we were expecting a value, record field with no scalar
828                    if let Some(name) = pending_field_name.take() {
829                        evidence.push(FieldEvidence {
830                            name,
831                            location: FieldLocationHint::KeyValue,
832                            value_type: None,
833                            scalar_value: None,
834                        });
835                    }
836                }
837                ParseEventKind::SequenceEnd => {
838                    depth -= 1;
839                }
840                ParseEventKind::FieldKey(key) => {
841                    // If there's a pending field, record it without a value
842                    if let Some(name) = pending_field_name.take() {
843                        evidence.push(FieldEvidence {
844                            name,
845                            location: FieldLocationHint::KeyValue,
846                            value_type: None,
847                            scalar_value: None,
848                        });
849                    }
850                    if depth == 1 {
851                        // Top-level field - save name, wait for value
852                        pending_field_name = key.name().cloned();
853                    }
854                }
855                ParseEventKind::Scalar(scalar) => {
856                    if let Some(name) = pending_field_name.take() {
857                        // Record field with its scalar value
858                        evidence.push(FieldEvidence {
859                            name,
860                            location: FieldLocationHint::KeyValue,
861                            value_type: None,
862                            scalar_value: Some(scalar),
863                        });
864                    }
865                }
866                ParseEventKind::OrderedField | ParseEventKind::VariantTag(_) => {}
867            }
868        }
869
870        // Handle any remaining pending field
871        if let Some(name) = pending_field_name.take() {
872            evidence.push(FieldEvidence {
873                name,
874                location: FieldLocationHint::KeyValue,
875                value_type: None,
876                scalar_value: None,
877            });
878        }
879
880        self.restore(save_point);
881        Ok(evidence)
882    }
883
884    pub(crate) fn deserialize_list(
885        &mut self,
886        mut wip: Partial<'input, BORROW>,
887        is_byte_vec: bool,
888    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
889        trace!("deserialize_list: starting");
890
891        // Try the optimized byte sequence path for Vec<u8>
892        // (is_byte_vec is precomputed in TypePlan)
893        if is_byte_vec && self.parser.hint_byte_sequence() {
894            // Parser supports bulk byte reading - expect Scalar(Bytes(...))
895            let event = self.expect_event("bytes")?;
896            trace!(?event, "deserialize_list: got bytes event");
897
898            return match event.kind {
899                ParseEventKind::Scalar(ScalarValue::Bytes(bytes)) => {
900                    self.set_bytes_value(wip, bytes)
901                }
902                _ => Err(DeserializeError {
903                    span: Some(self.last_span),
904                    path: Some(wip.path()),
905                    kind: DeserializeErrorKind::UnexpectedToken {
906                        expected: "bytes",
907                        got: event.kind_name().into(),
908                    },
909                }),
910            };
911        }
912
913        // Fallback: element-by-element deserialization. Most self-describing
914        // parsers ignore this, but formats with ambiguous container syntax
915        // (for example Lua's `{}`) can use it to disambiguate empty sequences.
916        self.parser.hint_sequence();
917
918        let event = self.expect_event("value")?;
919        trace!(?event, "deserialize_list: got container start event");
920
921        // Expect SequenceStart for lists
922        match event.kind {
923            ParseEventKind::SequenceStart(_) => {
924                trace!("deserialize_list: got sequence start");
925            }
926            ParseEventKind::StructStart(kind) => {
927                return Err(DeserializeError {
928                    span: Some(self.last_span),
929                    path: Some(wip.path()),
930                    kind: DeserializeErrorKind::UnexpectedToken {
931                        expected: "array",
932                        got: kind.name().into(),
933                    },
934                });
935            }
936            _ => {
937                return Err(DeserializeError {
938                    span: Some(self.last_span),
939                    path: Some(wip.path()),
940                    kind: DeserializeErrorKind::UnexpectedToken {
941                        expected: "sequence start",
942                        got: event.kind_name().into(),
943                    },
944                });
945            }
946        };
947
948        // Count buffered items to pre-reserve capacity
949        let capacity_hint = self.count_buffered_sequence_items();
950        trace!("deserialize_list: capacity hint = {capacity_hint}");
951
952        // Initialize the list with capacity hint
953        wip = wip.init_list_with_capacity(capacity_hint)?;
954        trace!("deserialize_list: initialized list, starting loop");
955
956        loop {
957            let event = self.expect_peek("value")?;
958            trace!(?event, "deserialize_list: loop iteration");
959
960            // Check for end of sequence
961            if matches!(event.kind, ParseEventKind::SequenceEnd) {
962                self.expect_event("value")?;
963                trace!("deserialize_list: reached end of sequence");
964                break;
965            }
966
967            trace!("deserialize_list: deserializing list item");
968            wip = wip
969                .begin_list_item()?
970                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
971                .end()?;
972        }
973
974        trace!("deserialize_list: completed");
975        Ok(wip)
976    }
977
978    pub(crate) fn deserialize_array(
979        &mut self,
980        mut wip: Partial<'input, BORROW>,
981    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
982        let _guard = SpanGuard::new(self.last_span);
983        // Get the fixed array length from the type definition
984        let array_len = match &wip.shape().def {
985            Def::Array(array_def) => array_def.n,
986            _ => {
987                return Err(DeserializeErrorKind::UnexpectedToken {
988                    expected: "array",
989                    got: format!("{:?}", wip.shape().def).into(),
990                }
991                .with_span(self.last_span));
992            }
993        };
994
995        // Hint that a fixed-size array is expected. Most self-describing parsers
996        // ignore this, but formats with ambiguous container syntax can use it to
997        // disambiguate empty arrays.
998        self.parser.hint_array(array_len);
999
1000        let event = self.expect_event("value")?;
1001
1002        // Expect SequenceStart for arrays
1003        match event.kind {
1004            ParseEventKind::SequenceStart(_) => {}
1005            ParseEventKind::StructStart(kind) => {
1006                return Err(DeserializeError {
1007                    span: Some(self.last_span),
1008                    path: Some(wip.path()),
1009                    kind: DeserializeErrorKind::UnexpectedToken {
1010                        expected: "array",
1011                        got: kind.name().into(),
1012                    },
1013                });
1014            }
1015            _ => {
1016                return Err(DeserializeError {
1017                    span: Some(self.last_span),
1018                    path: Some(wip.path()),
1019                    kind: DeserializeErrorKind::UnexpectedToken {
1020                        expected: "sequence start for array",
1021                        got: event.kind_name().into(),
1022                    },
1023                });
1024            }
1025        };
1026
1027        // Transition to Array tracker state. This is important for empty arrays
1028        // like [u8; 0] which have no elements to initialize but still need
1029        // their tracker state set correctly for require_full_initialization to pass.
1030        wip = wip.init_array()?;
1031
1032        let mut index = 0usize;
1033        loop {
1034            let event = self.expect_peek("value")?;
1035
1036            // Check for end of sequence
1037            if matches!(event.kind, ParseEventKind::SequenceEnd) {
1038                self.expect_event("value")?;
1039                break;
1040            }
1041
1042            wip = wip
1043                .begin_nth_field(index)?
1044                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1045                .end()?;
1046            index += 1;
1047        }
1048
1049        Ok(wip)
1050    }
1051
1052    pub(crate) fn deserialize_set(
1053        &mut self,
1054        mut wip: Partial<'input, BORROW>,
1055    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
1056        let _guard = SpanGuard::new(self.last_span);
1057
1058        // Hint that a set is represented by a sequence. Most self-describing
1059        // parsers ignore this, but formats with ambiguous container syntax can
1060        // use it to disambiguate empty sets.
1061        self.parser.hint_sequence();
1062
1063        let event = self.expect_event("value")?;
1064
1065        // Expect SequenceStart for sets
1066        match event.kind {
1067            ParseEventKind::SequenceStart(_) => {}
1068            ParseEventKind::StructStart(kind) => {
1069                return Err(DeserializeError {
1070                    span: Some(self.last_span),
1071                    path: Some(wip.path()),
1072                    kind: DeserializeErrorKind::UnexpectedToken {
1073                        expected: "set",
1074                        got: kind.name().into(),
1075                    },
1076                });
1077            }
1078            _ => {
1079                return Err(DeserializeError {
1080                    span: Some(self.last_span),
1081                    path: Some(wip.path()),
1082                    kind: DeserializeErrorKind::UnexpectedToken {
1083                        expected: "sequence start for set",
1084                        got: event.kind_name().into(),
1085                    },
1086                });
1087            }
1088        };
1089
1090        // Initialize the set
1091        wip = wip.init_set()?;
1092
1093        loop {
1094            let event = self.expect_peek("value")?;
1095
1096            // Check for end of sequence
1097            if matches!(event.kind, ParseEventKind::SequenceEnd) {
1098                self.expect_event("value")?;
1099                break;
1100            }
1101
1102            wip = wip
1103                .begin_set_item()?
1104                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1105                .end()?;
1106        }
1107
1108        Ok(wip)
1109    }
1110
1111    pub(crate) fn deserialize_map(
1112        &mut self,
1113        mut wip: Partial<'input, BORROW>,
1114    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
1115        let _guard = SpanGuard::new(self.last_span);
1116
1117        // For non-self-describing formats, hint that a map is expected
1118        if self.is_non_self_describing() {
1119            self.parser.hint_map();
1120        }
1121
1122        let event = self.expect_event("value")?;
1123
1124        // Initialize the map
1125        wip = wip.init_map()?;
1126
1127        // Handle both self-describing (StructStart) and non-self-describing (SequenceStart) formats
1128        match event.kind {
1129            ParseEventKind::StructStart(_) => {
1130                // Self-describing format (e.g., JSON): maps are represented as objects
1131                loop {
1132                    let event = self.expect_event("value")?;
1133                    match event.kind {
1134                        ParseEventKind::StructEnd => break,
1135                        ParseEventKind::FieldKey(key) => {
1136                            // Begin key
1137                            wip = wip
1138                                .begin_key()?
1139                                .with(|w| {
1140                                    self.deserialize_map_key(w, key.name().cloned(), key.meta())
1141                                })?
1142                                .end()?;
1143
1144                            // Begin value
1145                            wip = wip
1146                                .begin_value()?
1147                                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1148                                .end()?;
1149                        }
1150                        _ => {
1151                            return Err(DeserializeError {
1152                                span: Some(self.last_span),
1153                                path: Some(wip.path()),
1154                                kind: DeserializeErrorKind::UnexpectedToken {
1155                                    expected: "field key or struct end for map",
1156                                    got: event.kind_name().into(),
1157                                },
1158                            });
1159                        }
1160                    }
1161                }
1162            }
1163            ParseEventKind::SequenceStart(_) => {
1164                // Non-self-describing format (e.g., postcard): maps are sequences of key-value pairs
1165                loop {
1166                    let event = self.expect_peek("value")?;
1167                    match event.kind {
1168                        ParseEventKind::SequenceEnd => {
1169                            self.expect_event("value")?;
1170                            break;
1171                        }
1172                        ParseEventKind::OrderedField => {
1173                            self.expect_event("value")?;
1174
1175                            // Deserialize key
1176                            wip = wip
1177                                .begin_key()?
1178                                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1179                                .end()?;
1180
1181                            // Deserialize value
1182                            wip = wip
1183                                .begin_value()?
1184                                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1185                                .end()?;
1186                        }
1187                        _ => {
1188                            return Err(DeserializeError {
1189                                span: Some(self.last_span),
1190                                path: Some(wip.path()),
1191                                kind: DeserializeErrorKind::UnexpectedToken {
1192                                    expected: "ordered field or sequence end for map",
1193                                    got: event.kind_name().into(),
1194                                },
1195                            });
1196                        }
1197                    }
1198                }
1199            }
1200            _ => {
1201                return Err(DeserializeError {
1202                    span: Some(self.last_span),
1203                    path: Some(wip.path()),
1204                    kind: DeserializeErrorKind::UnexpectedToken {
1205                        expected: "struct start or sequence start for map",
1206                        got: event.kind_name().into(),
1207                    },
1208                });
1209            }
1210        }
1211
1212        Ok(wip)
1213    }
1214
1215    pub(crate) fn deserialize_scalar(
1216        &mut self,
1217        mut wip: Partial<'input, BORROW>,
1218        scalar_type: Option<ScalarType>,
1219        is_from_str: bool,
1220    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
1221        // Only hint for non-self-describing formats (e.g., postcard)
1222        // Self-describing formats like JSON already know the types
1223        if self.is_non_self_describing() {
1224            let shape = wip.shape();
1225
1226            // First, try hint_opaque_scalar for types that may have format-specific
1227            // binary representations (e.g., UUID as 16 raw bytes in postcard)
1228            let opaque_handled = if scalar_type.is_some() {
1229                // Standard primitives are never opaque
1230                false
1231            } else {
1232                // For all other scalar types, ask the parser if it handles them specially
1233                // TODO: Consider using shape.id instead of type_identifier for faster matching
1234                self.parser.hint_opaque_scalar(shape.type_identifier, shape)
1235            };
1236
1237            // If the parser didn't handle the opaque type, fall back to standard hints
1238            if !opaque_handled {
1239                // Use precomputed is_from_str instead of runtime vtable check
1240                let hint = scalar_type_to_hint(scalar_type).or(if is_from_str {
1241                    Some(ScalarTypeHint::String)
1242                } else {
1243                    None
1244                });
1245                if let Some(hint) = hint {
1246                    self.parser.hint_scalar_type(hint);
1247                }
1248            }
1249        }
1250
1251        let event = self.expect_event("value")?;
1252
1253        match event.kind {
1254            ParseEventKind::Scalar(scalar) => {
1255                wip = self.set_scalar(wip, scalar)?;
1256                Ok(wip)
1257            }
1258            ParseEventKind::StructStart(_container_kind) => {
1259                // When deserializing into a scalar, extract the _arg value.
1260                let mut found_scalar: Option<ScalarValue<'input>> = None;
1261
1262                loop {
1263                    let inner_event = self.expect_event("field or struct end")?;
1264                    match inner_event.kind {
1265                        ParseEventKind::StructEnd => break,
1266                        ParseEventKind::FieldKey(key) => {
1267                            // Look for _arg field (single argument)
1268                            if key.name().map(|c| c.as_ref()) == Some("_arg") {
1269                                let value_event = self.expect_event("argument value")?;
1270                                if let ParseEventKind::Scalar(scalar) = value_event.kind {
1271                                    found_scalar = Some(scalar);
1272                                } else {
1273                                    // Skip non-scalar argument
1274                                    self.skip_value()?;
1275                                }
1276                            } else {
1277                                // Skip other fields (_node_name, _arguments, properties, etc.)
1278                                self.skip_value()?;
1279                            }
1280                        }
1281                        _ => {
1282                            // Skip unexpected events
1283                        }
1284                    }
1285                }
1286
1287                if let Some(scalar) = found_scalar {
1288                    wip = self.set_scalar(wip, scalar)?;
1289                    Ok(wip)
1290                } else {
1291                    Err(DeserializeError {
1292                        span: Some(self.last_span),
1293                        path: Some(wip.path()),
1294                        kind: DeserializeErrorKind::UnexpectedToken {
1295                            expected: "scalar value or node with argument",
1296                            got: "node without argument".into(),
1297                        },
1298                    })
1299                }
1300            }
1301            _ => Err(DeserializeError {
1302                span: Some(self.last_span),
1303                path: Some(wip.path()),
1304                kind: DeserializeErrorKind::UnexpectedToken {
1305                    expected: "scalar value",
1306                    got: event.kind_name().into(),
1307                },
1308            }),
1309        }
1310    }
1311
1312    /// Deserialize a map key from a string or tag.
1313    ///
1314    /// Format parsers typically emit string keys, but the target map might have non-string key types
1315    /// (e.g., integers, enums). This function parses the string key into the appropriate type:
1316    /// - String types: set directly
1317    /// - Enum unit variants: use select_variant_named
1318    /// - Integer types: parse the string as a number
1319    /// - Transparent newtypes: descend into the inner type
1320    /// - Option types: None key becomes None, Some(key) recurses into inner type
1321    /// - Metadata containers (like `Documented<T>`): populate doc/tag metadata and recurse into value
1322    ///
1323    /// The `meta.tag` is for formats like Styx where keys can be type patterns (e.g., `@string`).
1324    /// When present, it indicates the key was a tag rather than a bare identifier.
1325    pub(crate) fn deserialize_map_key(
1326        &mut self,
1327        mut wip: Partial<'input, BORROW>,
1328        key: Option<Cow<'input, str>>,
1329        meta: Option<&ValueMeta<'input>>,
1330    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
1331        let _guard = SpanGuard::new(self.last_span);
1332        let shape = wip.shape();
1333
1334        trace!(shape_name = %shape, shape_def = ?shape.def, ?key, ?meta, "deserialize_map_key");
1335
1336        let format_ns = self.parser.format_namespace();
1337        let (next_wip, began_proxy) =
1338            wip.begin_custom_deserialization_from_shape_with_format(format_ns)?;
1339        if began_proxy {
1340            return Ok(next_wip
1341                .with(|w| self.deserialize_map_key(w, key, meta))?
1342                .end()?);
1343        }
1344        wip = next_wip;
1345
1346        // Handle metadata containers (like `Documented<T>` or `ObjectKey`): populate metadata and recurse into value
1347        if shape.is_metadata_container() {
1348            trace!("deserialize_map_key: metadata container detected");
1349            let empty_meta = ValueMeta::default();
1350            let meta = meta.unwrap_or(&empty_meta);
1351
1352            // Find field info from the shape's struct type
1353            if let Type::User(UserType::Struct(st)) = &shape.ty {
1354                for field in st.fields {
1355                    match field.metadata_kind() {
1356                        Some(kind) => {
1357                            wip = wip.begin_field(field.effective_name())?;
1358                            wip = self.populate_metadata_field(wip, kind, meta)?;
1359                            wip = wip.end()?;
1360                        }
1361                        None => {
1362                            // This is the value field - recurse with the key and tag.
1363                            // Doc is already consumed by this container, but tag may be needed
1364                            // by a nested metadata container (e.g., Documented<ObjectKey>).
1365                            let inner_meta =
1366                                ValueMeta::builder().maybe_tag(meta.tag().cloned()).build();
1367                            wip = wip
1368                                .begin_field(field.effective_name())?
1369                                .with(|w| {
1370                                    self.deserialize_map_key(w, key.clone(), Some(&inner_meta))
1371                                })?
1372                                .end()?;
1373                        }
1374                    }
1375                }
1376            }
1377
1378            return Ok(wip);
1379        }
1380
1381        // Handle Option<T> key types: None key -> None variant, Some(key) -> Some(inner)
1382        if let Def::Option(_) = &shape.def {
1383            match key {
1384                None => {
1385                    // Unit key -> None variant (use set_default to mark as initialized)
1386                    wip = wip.set_default()?;
1387                    return Ok(wip);
1388                }
1389                Some(inner_key) => {
1390                    // Named key -> Some(inner)
1391                    return Ok(wip
1392                        .begin_some()?
1393                        .with(|w| self.deserialize_map_key(w, Some(inner_key), None))?
1394                        .end()?);
1395                }
1396            }
1397        }
1398
1399        // From here on, we need an actual key name.
1400        // For tagged keys (e.g., @schema in Styx), use the tag (with @ prefix) as the key.
1401        let key = key
1402            .or_else(|| {
1403                meta.and_then(|m| m.tag())
1404                    .filter(|t| !t.is_empty())
1405                    .map(|t| Cow::Owned(format!("@{}", t)))
1406            })
1407            .ok_or_else(|| DeserializeError {
1408                span: Some(self.last_span),
1409                path: Some(wip.path()),
1410                kind: DeserializeErrorKind::UnexpectedToken {
1411                    expected: "named key",
1412                    got: "unit key".into(),
1413                },
1414            })?;
1415
1416        // For transparent types (like UserId(String)), we need to use begin_inner
1417        // to set the inner value. But NOT for pointer types like &str or Cow<str>
1418        // which are handled directly.
1419        let is_pointer = matches!(shape.def, Def::Pointer(_));
1420        if shape.inner.is_some() && !is_pointer {
1421            return Ok(wip
1422                .begin_inner()?
1423                .with(|w| self.deserialize_map_key(w, Some(key), None))?
1424                .end()?);
1425        }
1426
1427        // Handle terminal cases (enum, numeric, string) via non-generic inner function
1428        use crate::deserializer::setters::{
1429            MapKeyTerminalResult, deserialize_map_key_terminal_inner,
1430        };
1431        match deserialize_map_key_terminal_inner(wip, key, self.last_span) {
1432            Ok(wip) => Ok(wip),
1433            Err(MapKeyTerminalResult::NeedsSetString { wip, s }) => self.set_string_value(wip, s),
1434            Err(MapKeyTerminalResult::Error(e)) => Err(e),
1435        }
1436    }
1437}
1438
1439/// Convert a ScalarType to a ScalarTypeHint for non-self-describing parsers.
1440///
1441/// Returns None for types that don't have a direct hint mapping (Unit, CowStr,
1442/// network addresses, ConstTypeId).
1443#[inline]
1444fn scalar_type_to_hint(scalar_type: Option<ScalarType>) -> Option<ScalarTypeHint> {
1445    match scalar_type? {
1446        ScalarType::Bool => Some(ScalarTypeHint::Bool),
1447        ScalarType::U8 => Some(ScalarTypeHint::U8),
1448        ScalarType::U16 => Some(ScalarTypeHint::U16),
1449        ScalarType::U32 => Some(ScalarTypeHint::U32),
1450        ScalarType::U64 => Some(ScalarTypeHint::U64),
1451        ScalarType::U128 => Some(ScalarTypeHint::U128),
1452        ScalarType::USize => Some(ScalarTypeHint::Usize),
1453        ScalarType::I8 => Some(ScalarTypeHint::I8),
1454        ScalarType::I16 => Some(ScalarTypeHint::I16),
1455        ScalarType::I32 => Some(ScalarTypeHint::I32),
1456        ScalarType::I64 => Some(ScalarTypeHint::I64),
1457        ScalarType::I128 => Some(ScalarTypeHint::I128),
1458        ScalarType::ISize => Some(ScalarTypeHint::Isize),
1459        ScalarType::F32 => Some(ScalarTypeHint::F32),
1460        ScalarType::F64 => Some(ScalarTypeHint::F64),
1461        ScalarType::Char => Some(ScalarTypeHint::Char),
1462        ScalarType::Str | ScalarType::String => Some(ScalarTypeHint::String),
1463        // Types that need special handling or FromStr fallback
1464        _ => None,
1465    }
1466}