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 if matches!(event.kind, ParseEventKind::OptionSome) {
579                let _ = self.expect_event("option some")?;
580                wip = wip
581                    .begin_some()?
582                    .with(|w| self.deserialize_value_recursive(w, opt_def.t))?
583                    .end()?;
584            } else {
585                wip = self.deserialize_value_recursive(wip, opt_def.t)?;
586            }
587            return Ok(wip);
588        }
589
590        // Handle smart pointers - unwrap to inner type
591        if let Def::Pointer(ptr_def) = &hint_shape.def
592            && let Some(pointee) = ptr_def.pointee()
593        {
594            return self.deserialize_value_recursive(wip, pointee);
595        }
596
597        // Handle transparent wrappers (but not collections)
598        if let Some(inner) = hint_shape.inner
599            && !matches!(
600                &hint_shape.def,
601                Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
602            )
603        {
604            return self.deserialize_value_recursive(wip, inner);
605        }
606
607        // Dispatch based on hint shape type
608        match &hint_shape.ty {
609            Type::User(UserType::Struct(struct_def)) => {
610                if matches!(struct_def.kind, StructKind::Tuple | StructKind::TupleStruct) {
611                    self.deserialize_tuple_dynamic(wip, struct_def.fields)
612                } else {
613                    self.deserialize_struct_dynamic(wip, struct_def.fields)
614                }
615            }
616            Type::User(UserType::Enum(enum_def)) => self.deserialize_enum_dynamic(wip, enum_def),
617            _ => match &hint_shape.def {
618                Def::Scalar => self.deserialize_scalar_dynamic(wip, hint_shape),
619                Def::List(list_def) => self.deserialize_list_dynamic(wip, list_def.t),
620                Def::Array(array_def) => {
621                    self.deserialize_array_dynamic(wip, array_def.t, array_def.n)
622                }
623                Def::Map(map_def) => self.deserialize_map_dynamic(wip, map_def.k, map_def.v),
624                Def::Set(set_def) => self.deserialize_list_dynamic(wip, set_def.t),
625                _ => Err(DeserializeErrorKind::Unsupported {
626                    message: format!(
627                        "unsupported hint shape for dynamic deserialization: {:?}",
628                        hint_shape.def
629                    )
630                    .into(),
631                }
632                .with_span(self.last_span)),
633            },
634        }
635    }
636
637    pub(crate) fn deserialize_option(
638        &mut self,
639        mut wip: Partial<'input, BORROW>,
640    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
641        let _guard = SpanGuard::new(self.last_span);
642
643        // Hint to non-self-describing parsers that an Option is expected
644        if self.is_non_self_describing() {
645            self.parser.hint_option();
646        }
647
648        let event = self.expect_peek("value for option")?;
649
650        // Treat both Null and Unit as None
651        // Unit is used by Styx for tags without payload (e.g., @string vs @string{...})
652        if matches!(
653            event.kind,
654            ParseEventKind::Scalar(ScalarValue::Null | ScalarValue::Unit)
655        ) {
656            // Consume the null/unit
657            let _ = self.expect_event("null or unit")?;
658            // Set to None (default)
659            wip = wip.set_default()?;
660        } else if matches!(event.kind, ParseEventKind::OptionSome) {
661            let _ = self.expect_event("option some")?;
662            wip = wip
663                .begin_some()?
664                .with(|w| self.deserialize_into_inner(w, MetaSource::FromEvents))?
665                .end()?;
666        } else {
667            // Some(value)
668            wip = wip
669                .begin_some()?
670                .with(|w| self.deserialize_into_inner(w, MetaSource::FromEvents))?
671                .end()?;
672        }
673        Ok(wip)
674    }
675
676    pub(crate) fn deserialize_struct(
677        &mut self,
678        wip: Partial<'input, BORROW>,
679    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
680        let struct_plan = wip.struct_plan().unwrap();
681        if struct_plan.has_flatten {
682            self.deserialize_struct_with_flatten(wip)
683        } else {
684            self.deserialize_struct_simple(wip)
685        }
686    }
687
688    pub(crate) fn deserialize_tuple(
689        &mut self,
690        mut wip: Partial<'input, BORROW>,
691        field_count: usize,
692        is_single_field_transparent: bool,
693    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
694        let _guard = SpanGuard::new(self.last_span);
695
696        // Special case: transparent newtypes (marked with #[facet(transparent)] or
697        // #[repr(transparent)]) can accept values directly without a sequence wrapper.
698        // This enables patterns like:
699        //   #[facet(transparent)]
700        //   struct Wrapper(i32);
701        //   toml: "value = 42"  ->  Wrapper(42)
702        // Plain tuple structs without the transparent attribute use array syntax.
703        //
704        // IMPORTANT: This check must come BEFORE hint_struct_fields() because transparent
705        // newtypes don't consume struct events - they deserialize the inner value directly.
706        // If we hint struct fields first, non-self-describing parsers will expect to emit
707        // StructStart, causing "unexpected token: got struct start" errors.
708        if is_single_field_transparent {
709            // Unwrap into field 0 and deserialize directly
710            return Ok(wip
711                .begin_nth_field(0)?
712                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
713                .end()?);
714        }
715
716        // Hint to non-self-describing parsers how many fields to expect
717        // Tuples are like positional structs, so we use hint_struct_fields
718        if self.is_non_self_describing() {
719            self.parser.hint_struct_fields(field_count);
720        }
721
722        // Special case: unit type () can accept Scalar(Unit) or Scalar(Null) directly
723        // This enables patterns like styx bare identifiers: { id, name } -> IndexMap<String, ()>
724        // and JSON null values for unit types (e.g., ConfigValue::Null(Spanned<()>))
725        if field_count == 0 {
726            let peeked = self.expect_peek("value")?;
727            if matches!(
728                peeked.kind,
729                ParseEventKind::Scalar(ScalarValue::Unit | ScalarValue::Null)
730            ) {
731                self.expect_event("value")?; // consume the unit/null scalar
732                return Ok(wip);
733            }
734        }
735
736        let event = self.expect_event("value")?;
737
738        // Accept either SequenceStart (JSON arrays) or StructStart (for
739        // non-self-describing formats like postcard where tuples are positional structs)
740        let struct_mode = match event.kind {
741            ParseEventKind::SequenceStart(_) => false,
742            // For non-self-describing formats, StructStart(Object) is valid for tuples
743            // because hint_struct_fields was called and tuples are positional structs
744            ParseEventKind::StructStart(_) if !self.parser.is_self_describing() => true,
745            // For self-describing formats like TOML/JSON, objects with numeric keys
746            // (e.g., { "0" = true, "1" = 1 }) are valid tuple representations
747            ParseEventKind::StructStart(ContainerKind::Object) => true,
748            ParseEventKind::StructStart(kind) => {
749                return Err(DeserializeError {
750                    span: Some(self.last_span),
751                    path: Some(wip.path()),
752                    kind: DeserializeErrorKind::UnexpectedToken {
753                        expected: "array",
754                        got: kind.name().into(),
755                    },
756                });
757            }
758            _ => {
759                return Err(DeserializeError {
760                    span: Some(self.last_span),
761                    path: Some(wip.path()),
762                    kind: DeserializeErrorKind::UnexpectedToken {
763                        expected: "sequence start for tuple",
764                        got: event.kind_name().into(),
765                    },
766                });
767            }
768        };
769
770        let mut index = 0usize;
771        loop {
772            let event = self.expect_peek("value")?;
773
774            // Check for end of container
775            if matches!(
776                event.kind,
777                ParseEventKind::SequenceEnd | ParseEventKind::StructEnd
778            ) {
779                self.expect_event("value")?;
780                break;
781            }
782
783            // In struct mode, skip FieldKey events
784            if struct_mode && matches!(event.kind, ParseEventKind::FieldKey(_)) {
785                self.expect_event("value")?;
786                continue;
787            }
788
789            // Select field by index
790            wip = wip
791                .begin_nth_field(index)?
792                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
793                .end()?;
794            index += 1;
795        }
796
797        Ok(wip)
798    }
799
800    /// Helper to collect field evidence using save/restore.
801    ///
802    /// This saves the deserializer state (parser position AND event buffer),
803    /// reads through the current struct to collect field names and their scalar
804    /// values, then restores the state.
805    pub(crate) fn collect_evidence(
806        &mut self,
807    ) -> Result<Vec<FieldEvidence<'input>>, DeserializeError> {
808        let save_point = self.save();
809
810        let mut evidence = Vec::new();
811        let mut depth = 0i32;
812        let mut pending_field_name: Option<Cow<'input, str>> = None;
813
814        // Read through the structure
815        while let Ok(event) = self.expect_event("evidence") {
816            match event.kind {
817                ParseEventKind::StructStart(_) => {
818                    depth += 1;
819                    // If we were expecting a value, record field with no scalar
820                    if depth > 1
821                        && let Some(name) = pending_field_name.take()
822                    {
823                        evidence.push(FieldEvidence {
824                            name,
825                            location: FieldLocationHint::KeyValue,
826                            value_type: None,
827                            scalar_value: None,
828                        });
829                    }
830                }
831                ParseEventKind::StructEnd => {
832                    depth -= 1;
833                    if depth == 0 {
834                        break;
835                    }
836                }
837                ParseEventKind::SequenceStart(_) => {
838                    depth += 1;
839                    // If we were expecting a value, record field with no scalar
840                    if let Some(name) = pending_field_name.take() {
841                        evidence.push(FieldEvidence {
842                            name,
843                            location: FieldLocationHint::KeyValue,
844                            value_type: None,
845                            scalar_value: None,
846                        });
847                    }
848                }
849                ParseEventKind::SequenceEnd => {
850                    depth -= 1;
851                }
852                ParseEventKind::FieldKey(key) => {
853                    // If there's a pending field, record it without a value
854                    if let Some(name) = pending_field_name.take() {
855                        evidence.push(FieldEvidence {
856                            name,
857                            location: FieldLocationHint::KeyValue,
858                            value_type: None,
859                            scalar_value: None,
860                        });
861                    }
862                    if depth == 1 {
863                        // Top-level field - save name, wait for value
864                        pending_field_name = key.name().cloned();
865                    }
866                }
867                ParseEventKind::Scalar(scalar) => {
868                    if let Some(name) = pending_field_name.take() {
869                        // Record field with its scalar value
870                        evidence.push(FieldEvidence {
871                            name,
872                            location: FieldLocationHint::KeyValue,
873                            value_type: None,
874                            scalar_value: Some(scalar),
875                        });
876                    }
877                }
878                ParseEventKind::OrderedField
879                | ParseEventKind::OptionSome
880                | ParseEventKind::VariantTag(_) => {}
881            }
882        }
883
884        // Handle any remaining pending field
885        if let Some(name) = pending_field_name.take() {
886            evidence.push(FieldEvidence {
887                name,
888                location: FieldLocationHint::KeyValue,
889                value_type: None,
890                scalar_value: None,
891            });
892        }
893
894        self.restore(save_point);
895        Ok(evidence)
896    }
897
898    pub(crate) fn deserialize_list(
899        &mut self,
900        mut wip: Partial<'input, BORROW>,
901        is_byte_vec: bool,
902    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
903        trace!("deserialize_list: starting");
904
905        // Try the optimized byte sequence path for Vec<u8>
906        // (is_byte_vec is precomputed in TypePlan)
907        if is_byte_vec && self.parser.hint_byte_sequence() {
908            // Parser supports bulk byte reading - expect Scalar(Bytes(...))
909            let event = self.expect_event("bytes")?;
910            trace!(?event, "deserialize_list: got bytes event");
911
912            return match event.kind {
913                ParseEventKind::Scalar(ScalarValue::Bytes(bytes)) => {
914                    self.set_bytes_value(wip, bytes)
915                }
916                _ => Err(DeserializeError {
917                    span: Some(self.last_span),
918                    path: Some(wip.path()),
919                    kind: DeserializeErrorKind::UnexpectedToken {
920                        expected: "bytes",
921                        got: event.kind_name().into(),
922                    },
923                }),
924            };
925        }
926
927        // Fallback: element-by-element deserialization. Most self-describing
928        // parsers ignore this, but formats with ambiguous container syntax
929        // (for example Lua's `{}`) can use it to disambiguate empty sequences.
930        self.parser.hint_sequence();
931
932        let event = self.expect_event("value")?;
933        trace!(?event, "deserialize_list: got container start event");
934
935        // Expect SequenceStart for lists
936        match event.kind {
937            ParseEventKind::SequenceStart(_) => {
938                trace!("deserialize_list: got sequence start");
939            }
940            ParseEventKind::StructStart(kind) => {
941                return Err(DeserializeError {
942                    span: Some(self.last_span),
943                    path: Some(wip.path()),
944                    kind: DeserializeErrorKind::UnexpectedToken {
945                        expected: "array",
946                        got: kind.name().into(),
947                    },
948                });
949            }
950            _ => {
951                return Err(DeserializeError {
952                    span: Some(self.last_span),
953                    path: Some(wip.path()),
954                    kind: DeserializeErrorKind::UnexpectedToken {
955                        expected: "sequence start",
956                        got: event.kind_name().into(),
957                    },
958                });
959            }
960        };
961
962        // Count buffered items to pre-reserve capacity
963        let capacity_hint = self.count_buffered_sequence_items();
964        trace!("deserialize_list: capacity hint = {capacity_hint}");
965
966        // Initialize the list with capacity hint
967        wip = wip.init_list_with_capacity(capacity_hint)?;
968        trace!("deserialize_list: initialized list, starting loop");
969
970        loop {
971            let event = self.expect_peek("value")?;
972            trace!(?event, "deserialize_list: loop iteration");
973
974            // Check for end of sequence
975            if matches!(event.kind, ParseEventKind::SequenceEnd) {
976                self.expect_event("value")?;
977                trace!("deserialize_list: reached end of sequence");
978                break;
979            }
980
981            trace!("deserialize_list: deserializing list item");
982            wip = wip
983                .begin_list_item()?
984                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
985                .end()?;
986        }
987
988        trace!("deserialize_list: completed");
989        Ok(wip)
990    }
991
992    pub(crate) fn deserialize_array(
993        &mut self,
994        mut wip: Partial<'input, BORROW>,
995    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
996        let _guard = SpanGuard::new(self.last_span);
997        // Get the fixed array length from the type definition
998        let array_len = match &wip.shape().def {
999            Def::Array(array_def) => array_def.n,
1000            _ => {
1001                return Err(DeserializeErrorKind::UnexpectedToken {
1002                    expected: "array",
1003                    got: format!("{:?}", wip.shape().def).into(),
1004                }
1005                .with_span(self.last_span));
1006            }
1007        };
1008
1009        // Hint that a fixed-size array is expected. Most self-describing parsers
1010        // ignore this, but formats with ambiguous container syntax can use it to
1011        // disambiguate empty arrays.
1012        self.parser.hint_array(array_len);
1013
1014        let event = self.expect_event("value")?;
1015
1016        // Expect SequenceStart for arrays
1017        match event.kind {
1018            ParseEventKind::SequenceStart(_) => {}
1019            ParseEventKind::StructStart(kind) => {
1020                return Err(DeserializeError {
1021                    span: Some(self.last_span),
1022                    path: Some(wip.path()),
1023                    kind: DeserializeErrorKind::UnexpectedToken {
1024                        expected: "array",
1025                        got: kind.name().into(),
1026                    },
1027                });
1028            }
1029            _ => {
1030                return Err(DeserializeError {
1031                    span: Some(self.last_span),
1032                    path: Some(wip.path()),
1033                    kind: DeserializeErrorKind::UnexpectedToken {
1034                        expected: "sequence start for array",
1035                        got: event.kind_name().into(),
1036                    },
1037                });
1038            }
1039        };
1040
1041        // Transition to Array tracker state. This is important for empty arrays
1042        // like [u8; 0] which have no elements to initialize but still need
1043        // their tracker state set correctly for require_full_initialization to pass.
1044        wip = wip.init_array()?;
1045
1046        let mut index = 0usize;
1047        loop {
1048            let event = self.expect_peek("value")?;
1049
1050            // Check for end of sequence
1051            if matches!(event.kind, ParseEventKind::SequenceEnd) {
1052                self.expect_event("value")?;
1053                break;
1054            }
1055
1056            wip = wip
1057                .begin_nth_field(index)?
1058                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1059                .end()?;
1060            index += 1;
1061        }
1062
1063        Ok(wip)
1064    }
1065
1066    pub(crate) fn deserialize_set(
1067        &mut self,
1068        mut wip: Partial<'input, BORROW>,
1069    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
1070        let _guard = SpanGuard::new(self.last_span);
1071
1072        // Hint that a set is represented by a sequence. Most self-describing
1073        // parsers ignore this, but formats with ambiguous container syntax can
1074        // use it to disambiguate empty sets.
1075        self.parser.hint_sequence();
1076
1077        let event = self.expect_event("value")?;
1078
1079        // Expect SequenceStart for sets
1080        match event.kind {
1081            ParseEventKind::SequenceStart(_) => {}
1082            ParseEventKind::StructStart(kind) => {
1083                return Err(DeserializeError {
1084                    span: Some(self.last_span),
1085                    path: Some(wip.path()),
1086                    kind: DeserializeErrorKind::UnexpectedToken {
1087                        expected: "set",
1088                        got: kind.name().into(),
1089                    },
1090                });
1091            }
1092            _ => {
1093                return Err(DeserializeError {
1094                    span: Some(self.last_span),
1095                    path: Some(wip.path()),
1096                    kind: DeserializeErrorKind::UnexpectedToken {
1097                        expected: "sequence start for set",
1098                        got: event.kind_name().into(),
1099                    },
1100                });
1101            }
1102        };
1103
1104        // Initialize the set
1105        wip = wip.init_set()?;
1106
1107        loop {
1108            let event = self.expect_peek("value")?;
1109
1110            // Check for end of sequence
1111            if matches!(event.kind, ParseEventKind::SequenceEnd) {
1112                self.expect_event("value")?;
1113                break;
1114            }
1115
1116            wip = wip
1117                .begin_set_item()?
1118                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1119                .end()?;
1120        }
1121
1122        Ok(wip)
1123    }
1124
1125    pub(crate) fn deserialize_map(
1126        &mut self,
1127        mut wip: Partial<'input, BORROW>,
1128    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
1129        let _guard = SpanGuard::new(self.last_span);
1130
1131        // For non-self-describing formats, hint that a map is expected
1132        if self.is_non_self_describing() {
1133            self.parser.hint_map();
1134        }
1135
1136        let event = self.expect_event("value")?;
1137
1138        // Initialize the map
1139        wip = wip.init_map()?;
1140
1141        // Handle both self-describing (StructStart) and non-self-describing (SequenceStart) formats
1142        match event.kind {
1143            ParseEventKind::StructStart(_) => {
1144                // Self-describing format (e.g., JSON): maps are represented as objects
1145                loop {
1146                    let event = self.expect_event("value")?;
1147                    match event.kind {
1148                        ParseEventKind::StructEnd => break,
1149                        ParseEventKind::FieldKey(key) => {
1150                            // Begin key
1151                            wip = wip
1152                                .begin_key()?
1153                                .with(|w| {
1154                                    self.deserialize_map_key(w, key.name().cloned(), key.meta())
1155                                })?
1156                                .end()?;
1157
1158                            // Begin value
1159                            wip = wip
1160                                .begin_value()?
1161                                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1162                                .end()?;
1163                        }
1164                        _ => {
1165                            return Err(DeserializeError {
1166                                span: Some(self.last_span),
1167                                path: Some(wip.path()),
1168                                kind: DeserializeErrorKind::UnexpectedToken {
1169                                    expected: "field key or struct end for map",
1170                                    got: event.kind_name().into(),
1171                                },
1172                            });
1173                        }
1174                    }
1175                }
1176            }
1177            ParseEventKind::SequenceStart(_) => {
1178                // Non-self-describing format (e.g., postcard): maps are sequences of key-value pairs
1179                loop {
1180                    let event = self.expect_peek("value")?;
1181                    match event.kind {
1182                        ParseEventKind::SequenceEnd => {
1183                            self.expect_event("value")?;
1184                            break;
1185                        }
1186                        ParseEventKind::OrderedField => {
1187                            self.expect_event("value")?;
1188
1189                            // Deserialize key
1190                            wip = wip
1191                                .begin_key()?
1192                                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1193                                .end()?;
1194
1195                            // Deserialize value
1196                            wip = wip
1197                                .begin_value()?
1198                                .with(|w| self.deserialize_into(w, MetaSource::FromEvents))?
1199                                .end()?;
1200                        }
1201                        _ => {
1202                            return Err(DeserializeError {
1203                                span: Some(self.last_span),
1204                                path: Some(wip.path()),
1205                                kind: DeserializeErrorKind::UnexpectedToken {
1206                                    expected: "ordered field or sequence end for map",
1207                                    got: event.kind_name().into(),
1208                                },
1209                            });
1210                        }
1211                    }
1212                }
1213            }
1214            _ => {
1215                return Err(DeserializeError {
1216                    span: Some(self.last_span),
1217                    path: Some(wip.path()),
1218                    kind: DeserializeErrorKind::UnexpectedToken {
1219                        expected: "struct start or sequence start for map",
1220                        got: event.kind_name().into(),
1221                    },
1222                });
1223            }
1224        }
1225
1226        Ok(wip)
1227    }
1228
1229    pub(crate) fn deserialize_scalar(
1230        &mut self,
1231        mut wip: Partial<'input, BORROW>,
1232        scalar_type: Option<ScalarType>,
1233        is_from_str: bool,
1234    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
1235        // Only hint for non-self-describing formats (e.g., postcard)
1236        // Self-describing formats like JSON already know the types
1237        if self.is_non_self_describing() {
1238            let shape = wip.shape();
1239
1240            // First, try hint_opaque_scalar for types that may have format-specific
1241            // binary representations (e.g., UUID as 16 raw bytes in postcard)
1242            let opaque_handled = if scalar_type.is_some() {
1243                // Standard primitives are never opaque
1244                false
1245            } else {
1246                // For all other scalar types, ask the parser if it handles them specially
1247                // TODO: Consider using shape.id instead of type_identifier for faster matching
1248                self.parser.hint_opaque_scalar(shape.type_identifier, shape)
1249            };
1250
1251            // If the parser didn't handle the opaque type, fall back to standard hints
1252            if !opaque_handled {
1253                // Use precomputed is_from_str instead of runtime vtable check
1254                let hint = scalar_type_to_hint(scalar_type).or(if is_from_str {
1255                    Some(ScalarTypeHint::String)
1256                } else {
1257                    None
1258                });
1259                if let Some(hint) = hint {
1260                    self.parser.hint_scalar_type(hint);
1261                }
1262            }
1263        }
1264
1265        let event = self.expect_event("value")?;
1266
1267        match event.kind {
1268            ParseEventKind::Scalar(scalar) => {
1269                wip = self.set_scalar(wip, scalar)?;
1270                Ok(wip)
1271            }
1272            ParseEventKind::StructStart(_container_kind) => {
1273                // When deserializing into a scalar, extract the _arg value.
1274                let mut found_scalar: Option<ScalarValue<'input>> = None;
1275
1276                loop {
1277                    let inner_event = self.expect_event("field or struct end")?;
1278                    match inner_event.kind {
1279                        ParseEventKind::StructEnd => break,
1280                        ParseEventKind::FieldKey(key) => {
1281                            // Look for _arg field (single argument)
1282                            if key.name().map(|c| c.as_ref()) == Some("_arg") {
1283                                let value_event = self.expect_event("argument value")?;
1284                                if let ParseEventKind::Scalar(scalar) = value_event.kind {
1285                                    found_scalar = Some(scalar);
1286                                } else {
1287                                    // Skip non-scalar argument
1288                                    self.skip_value()?;
1289                                }
1290                            } else {
1291                                // Skip other fields (_node_name, _arguments, properties, etc.)
1292                                self.skip_value()?;
1293                            }
1294                        }
1295                        _ => {
1296                            // Skip unexpected events
1297                        }
1298                    }
1299                }
1300
1301                if let Some(scalar) = found_scalar {
1302                    wip = self.set_scalar(wip, scalar)?;
1303                    Ok(wip)
1304                } else {
1305                    Err(DeserializeError {
1306                        span: Some(self.last_span),
1307                        path: Some(wip.path()),
1308                        kind: DeserializeErrorKind::UnexpectedToken {
1309                            expected: "scalar value or node with argument",
1310                            got: "node without argument".into(),
1311                        },
1312                    })
1313                }
1314            }
1315            _ => Err(DeserializeError {
1316                span: Some(self.last_span),
1317                path: Some(wip.path()),
1318                kind: DeserializeErrorKind::UnexpectedToken {
1319                    expected: "scalar value",
1320                    got: event.kind_name().into(),
1321                },
1322            }),
1323        }
1324    }
1325
1326    /// Deserialize a map key from a string or tag.
1327    ///
1328    /// Format parsers typically emit string keys, but the target map might have non-string key types
1329    /// (e.g., integers, enums). This function parses the string key into the appropriate type:
1330    /// - String types: set directly
1331    /// - Enum unit variants: use select_variant_named
1332    /// - Integer types: parse the string as a number
1333    /// - Transparent newtypes: descend into the inner type
1334    /// - Option types: None key becomes None, Some(key) recurses into inner type
1335    /// - Metadata containers (like `Documented<T>`): populate doc/tag metadata and recurse into value
1336    ///
1337    /// The `meta.tag` is for formats like Styx where keys can be type patterns (e.g., `@string`).
1338    /// When present, it indicates the key was a tag rather than a bare identifier.
1339    pub(crate) fn deserialize_map_key(
1340        &mut self,
1341        mut wip: Partial<'input, BORROW>,
1342        key: Option<Cow<'input, str>>,
1343        meta: Option<&ValueMeta<'input>>,
1344    ) -> Result<Partial<'input, BORROW>, DeserializeError> {
1345        let _guard = SpanGuard::new(self.last_span);
1346        let shape = wip.shape();
1347
1348        trace!(shape_name = %shape, shape_def = ?shape.def, ?key, ?meta, "deserialize_map_key");
1349
1350        let format_ns = self.parser.format_namespace();
1351        let (next_wip, began_proxy) =
1352            wip.begin_custom_deserialization_from_shape_with_format(format_ns)?;
1353        if began_proxy {
1354            return Ok(next_wip
1355                .with(|w| self.deserialize_map_key(w, key, meta))?
1356                .end()?);
1357        }
1358        wip = next_wip;
1359
1360        // Handle metadata containers (like `Documented<T>` or `ObjectKey`): populate metadata and recurse into value
1361        if shape.is_metadata_container() {
1362            trace!("deserialize_map_key: metadata container detected");
1363            let empty_meta = ValueMeta::default();
1364            let meta = meta.unwrap_or(&empty_meta);
1365
1366            // Find field info from the shape's struct type
1367            if let Type::User(UserType::Struct(st)) = &shape.ty {
1368                for field in st.fields {
1369                    match field.metadata_kind() {
1370                        Some(kind) => {
1371                            wip = wip.begin_field(field.effective_name())?;
1372                            wip = self.populate_metadata_field(wip, kind, meta)?;
1373                            wip = wip.end()?;
1374                        }
1375                        None => {
1376                            // This is the value field - recurse with the key and tag.
1377                            // Doc is already consumed by this container, but tag may be needed
1378                            // by a nested metadata container (e.g., Documented<ObjectKey>).
1379                            let inner_meta =
1380                                ValueMeta::builder().maybe_tag(meta.tag().cloned()).build();
1381                            wip = wip
1382                                .begin_field(field.effective_name())?
1383                                .with(|w| {
1384                                    self.deserialize_map_key(w, key.clone(), Some(&inner_meta))
1385                                })?
1386                                .end()?;
1387                        }
1388                    }
1389                }
1390            }
1391
1392            return Ok(wip);
1393        }
1394
1395        // Handle Option<T> key types: None key -> None variant, Some(key) -> Some(inner)
1396        if let Def::Option(_) = &shape.def {
1397            match key {
1398                None => {
1399                    // Unit key -> None variant (use set_default to mark as initialized)
1400                    wip = wip.set_default()?;
1401                    return Ok(wip);
1402                }
1403                Some(inner_key) => {
1404                    // Named key -> Some(inner)
1405                    return Ok(wip
1406                        .begin_some()?
1407                        .with(|w| self.deserialize_map_key(w, Some(inner_key), None))?
1408                        .end()?);
1409                }
1410            }
1411        }
1412
1413        // From here on, we need an actual key name.
1414        // For tagged keys (e.g., @schema in Styx), use the tag (with @ prefix) as the key.
1415        let key = key
1416            .or_else(|| {
1417                meta.and_then(|m| m.tag())
1418                    .filter(|t| !t.is_empty())
1419                    .map(|t| Cow::Owned(format!("@{}", t)))
1420            })
1421            .ok_or_else(|| DeserializeError {
1422                span: Some(self.last_span),
1423                path: Some(wip.path()),
1424                kind: DeserializeErrorKind::UnexpectedToken {
1425                    expected: "named key",
1426                    got: "unit key".into(),
1427                },
1428            })?;
1429
1430        // For transparent types (like UserId(String)), we need to use begin_inner
1431        // to set the inner value. But NOT for pointer types like &str or Cow<str>
1432        // which are handled directly.
1433        let is_pointer = matches!(shape.def, Def::Pointer(_));
1434        if shape.inner.is_some() && !is_pointer {
1435            return Ok(wip
1436                .begin_inner()?
1437                .with(|w| self.deserialize_map_key(w, Some(key), None))?
1438                .end()?);
1439        }
1440
1441        // Handle terminal cases (enum, numeric, string) via non-generic inner function
1442        use crate::deserializer::setters::{
1443            MapKeyTerminalResult, deserialize_map_key_terminal_inner,
1444        };
1445        match deserialize_map_key_terminal_inner(wip, key, self.last_span) {
1446            Ok(wip) => Ok(wip),
1447            Err(MapKeyTerminalResult::NeedsSetString { wip, s }) => self.set_string_value(wip, s),
1448            Err(MapKeyTerminalResult::Error(e)) => Err(e),
1449        }
1450    }
1451}
1452
1453/// Convert a ScalarType to a ScalarTypeHint for non-self-describing parsers.
1454///
1455/// Returns None for types that don't have a direct hint mapping (Unit, CowStr,
1456/// network addresses, ConstTypeId).
1457#[inline]
1458fn scalar_type_to_hint(scalar_type: Option<ScalarType>) -> Option<ScalarTypeHint> {
1459    match scalar_type? {
1460        ScalarType::Bool => Some(ScalarTypeHint::Bool),
1461        ScalarType::U8 => Some(ScalarTypeHint::U8),
1462        ScalarType::U16 => Some(ScalarTypeHint::U16),
1463        ScalarType::U32 => Some(ScalarTypeHint::U32),
1464        ScalarType::U64 => Some(ScalarTypeHint::U64),
1465        ScalarType::U128 => Some(ScalarTypeHint::U128),
1466        ScalarType::USize => Some(ScalarTypeHint::Usize),
1467        ScalarType::I8 => Some(ScalarTypeHint::I8),
1468        ScalarType::I16 => Some(ScalarTypeHint::I16),
1469        ScalarType::I32 => Some(ScalarTypeHint::I32),
1470        ScalarType::I64 => Some(ScalarTypeHint::I64),
1471        ScalarType::I128 => Some(ScalarTypeHint::I128),
1472        ScalarType::ISize => Some(ScalarTypeHint::Isize),
1473        ScalarType::F32 => Some(ScalarTypeHint::F32),
1474        ScalarType::F64 => Some(ScalarTypeHint::F64),
1475        ScalarType::Char => Some(ScalarTypeHint::Char),
1476        ScalarType::Str | ScalarType::String => Some(ScalarTypeHint::String),
1477        // Types that need special handling or FromStr fallback
1478        _ => None,
1479    }
1480}