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