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