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