facet_json/
deserialize.rs

1//! Recursive descent JSON deserializer using facet-reflect.
2
3use alloc::borrow::Cow;
4use alloc::format;
5use alloc::string::{String, ToString};
6use alloc::vec::Vec;
7use core::fmt::{self, Display};
8use core::ptr;
9
10use alloc::collections::{BTreeMap, BTreeSet};
11
12use facet_core::{
13    Characteristic, Def, Facet, KnownPointer, NumericType, PrimitiveType, ScalarType, SequenceType,
14    Shape, ShapeLayout, StructKind, Type, UserType,
15};
16use facet_reflect::{Partial, ReflectError, is_spanned_shape};
17use facet_solver::{FieldInfo, PathSegment, Schema, Solver, VariantsByFormat, specificity_score};
18
19use crate::RawJson;
20use crate::adapter::{AdapterError, AdapterErrorKind, SliceAdapter, SpannedAdapterToken, Token};
21use crate::scanner::ScanErrorKind;
22use facet_reflect::Span;
23
24/// Find the best matching field name from a list of expected fields.
25/// Returns Some(suggestion) if a match with similarity >= 0.6 is found.
26fn find_similar_field<'a>(unknown: &str, expected: &[&'a str]) -> Option<&'a str> {
27    let mut best_match: Option<(&'a str, f64)> = None;
28
29    for &candidate in expected {
30        let similarity = strsim::jaro_winkler(unknown, candidate);
31        if similarity >= 0.6 && best_match.is_none_or(|(_, best_sim)| similarity > best_sim) {
32            best_match = Some((candidate, similarity));
33        }
34    }
35
36    best_match.map(|(name, _)| name)
37}
38
39// ============================================================================
40// Error Types
41// ============================================================================
42
43/// Error type for JSON deserialization.
44#[derive(Debug)]
45pub struct JsonError {
46    /// The specific kind of error
47    pub kind: JsonErrorKind,
48    /// Source span where the error occurred
49    pub span: Option<Span>,
50    /// The source input (for diagnostics)
51    pub source_code: Option<String>,
52}
53
54impl Display for JsonError {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        write!(f, "{}", self.kind)
57    }
58}
59
60impl std::error::Error for JsonError {}
61
62impl miette::Diagnostic for JsonError {
63    fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
64        Some(Box::new(self.kind.code()))
65    }
66
67    fn source_code(&self) -> Option<&dyn miette::SourceCode> {
68        self.source_code
69            .as_ref()
70            .map(|s| s as &dyn miette::SourceCode)
71    }
72
73    fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
74        // Handle MissingField with multiple spans
75        if let JsonErrorKind::MissingField {
76            field,
77            object_start,
78            object_end,
79        } = &self.kind
80        {
81            let mut labels = Vec::new();
82            if let Some(start) = object_start {
83                labels.push(miette::LabeledSpan::new(
84                    Some("object started here".into()),
85                    start.offset,
86                    start.len,
87                ));
88            }
89            if let Some(end) = object_end {
90                labels.push(miette::LabeledSpan::new(
91                    Some(format!("object ended without field `{field}`")),
92                    end.offset,
93                    end.len,
94                ));
95            }
96            if labels.is_empty() {
97                return None;
98            }
99            return Some(Box::new(labels.into_iter()));
100        }
101
102        // Default: single span with label
103        let span = self.span?;
104        Some(Box::new(core::iter::once(miette::LabeledSpan::new(
105            Some(self.kind.label()),
106            span.offset,
107            span.len,
108        ))))
109    }
110}
111
112impl JsonError {
113    /// Create a new error with span information
114    pub fn new(kind: JsonErrorKind, span: Span) -> Self {
115        JsonError {
116            kind,
117            span: Some(span),
118            source_code: None,
119        }
120    }
121
122    /// Create an error without span information
123    pub fn without_span(kind: JsonErrorKind) -> Self {
124        JsonError {
125            kind,
126            span: None,
127            source_code: None,
128        }
129    }
130
131    /// Attach source code for rich diagnostics
132    pub fn with_source(mut self, source: &str) -> Self {
133        self.source_code = Some(source.to_string());
134        self
135    }
136}
137
138#[inline(never)]
139#[cold]
140fn attach_source_cold(mut err: JsonError, source: Option<&str>) -> JsonError {
141    if let Some(src) = source {
142        err.source_code = Some(src.to_string());
143    }
144    err
145}
146
147/// Specific error kinds for JSON deserialization
148#[derive(Debug)]
149pub enum JsonErrorKind {
150    /// Scanner/adapter error
151    Scan(ScanErrorKind),
152    /// Scanner error with type context (what type was being parsed)
153    ScanWithContext {
154        /// The underlying scan error
155        error: ScanErrorKind,
156        /// The type that was being parsed
157        expected_type: &'static str,
158    },
159    /// Unexpected token
160    UnexpectedToken {
161        /// The token that was found
162        got: String,
163        /// What was expected instead
164        expected: &'static str,
165    },
166    /// Unexpected end of input
167    UnexpectedEof {
168        /// What was expected before EOF
169        expected: &'static str,
170    },
171    /// Type mismatch
172    TypeMismatch {
173        /// The expected type
174        expected: &'static str,
175        /// The actual type found
176        got: &'static str,
177    },
178    /// Unknown field in struct
179    UnknownField {
180        /// The unknown field name
181        field: String,
182        /// List of valid field names
183        expected: Vec<&'static str>,
184        /// Suggested field name (if similar to an expected field)
185        suggestion: Option<&'static str>,
186    },
187    /// Missing required field
188    MissingField {
189        /// The name of the missing field
190        field: &'static str,
191        /// Span of the object start (opening brace)
192        object_start: Option<Span>,
193        /// Span of the object end (closing brace)
194        object_end: Option<Span>,
195    },
196    /// Invalid value for type
197    InvalidValue {
198        /// Description of why the value is invalid
199        message: String,
200    },
201    /// Reflection error from facet-reflect
202    Reflect(ReflectError),
203    /// Number out of range
204    NumberOutOfRange {
205        /// The numeric value that was out of range
206        value: String,
207        /// The target type that couldn't hold the value
208        target_type: &'static str,
209    },
210    /// Duplicate key in object
211    DuplicateKey {
212        /// The key that appeared more than once
213        key: String,
214    },
215    /// Invalid UTF-8 in string
216    InvalidUtf8,
217    /// Solver error (for flattened types)
218    Solver(String),
219    /// I/O error (for streaming deserialization)
220    Io(String),
221}
222
223impl Display for JsonErrorKind {
224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225        match self {
226            JsonErrorKind::Scan(e) => write!(f, "{e:?}"),
227            JsonErrorKind::ScanWithContext {
228                error,
229                expected_type,
230            } => {
231                write!(f, "{error:?} (while parsing {expected_type})")
232            }
233            JsonErrorKind::UnexpectedToken { got, expected } => {
234                write!(f, "unexpected token: got {got}, expected {expected}")
235            }
236            JsonErrorKind::UnexpectedEof { expected } => {
237                write!(f, "unexpected end of input, expected {expected}")
238            }
239            JsonErrorKind::TypeMismatch { expected, got } => {
240                write!(f, "type mismatch: expected {expected}, got {got}")
241            }
242            JsonErrorKind::UnknownField {
243                field,
244                expected,
245                suggestion,
246            } => {
247                write!(f, "unknown field `{field}`, expected one of: {expected:?}")?;
248                if let Some(suggested) = suggestion {
249                    write!(f, " (did you mean `{suggested}`?)")?;
250                }
251                Ok(())
252            }
253            JsonErrorKind::MissingField { field, .. } => {
254                write!(f, "missing required field `{field}`")
255            }
256            JsonErrorKind::InvalidValue { message } => {
257                write!(f, "invalid value: {message}")
258            }
259            JsonErrorKind::Reflect(e) => write!(f, "reflection error: {e}"),
260            JsonErrorKind::NumberOutOfRange { value, target_type } => {
261                write!(f, "number `{value}` out of range for {target_type}")
262            }
263            JsonErrorKind::DuplicateKey { key } => {
264                write!(f, "duplicate key `{key}`")
265            }
266            JsonErrorKind::InvalidUtf8 => write!(f, "invalid UTF-8 sequence"),
267            JsonErrorKind::Solver(msg) => write!(f, "solver error: {msg}"),
268            JsonErrorKind::Io(msg) => write!(f, "I/O error: {msg}"),
269        }
270    }
271}
272
273impl JsonErrorKind {
274    /// Get an error code for this kind of error.
275    pub fn code(&self) -> &'static str {
276        match self {
277            JsonErrorKind::Scan(_) => "json::scan",
278            JsonErrorKind::ScanWithContext { .. } => "json::scan",
279            JsonErrorKind::UnexpectedToken { .. } => "json::unexpected_token",
280            JsonErrorKind::UnexpectedEof { .. } => "json::unexpected_eof",
281            JsonErrorKind::TypeMismatch { .. } => "json::type_mismatch",
282            JsonErrorKind::UnknownField { .. } => "json::unknown_field",
283            JsonErrorKind::MissingField { .. } => "json::missing_field",
284            JsonErrorKind::InvalidValue { .. } => "json::invalid_value",
285            JsonErrorKind::Reflect(_) => "json::reflect",
286            JsonErrorKind::NumberOutOfRange { .. } => "json::number_out_of_range",
287            JsonErrorKind::DuplicateKey { .. } => "json::duplicate_key",
288            JsonErrorKind::InvalidUtf8 => "json::invalid_utf8",
289            JsonErrorKind::Solver(_) => "json::solver",
290            JsonErrorKind::Io(_) => "json::io",
291        }
292    }
293
294    /// Get a label describing where/what the error points to.
295    pub fn label(&self) -> String {
296        match self {
297            JsonErrorKind::Scan(e) => match e {
298                ScanErrorKind::UnexpectedChar(c) => format!("unexpected '{c}'"),
299                ScanErrorKind::UnexpectedEof(ctx) => format!("unexpected end of input {ctx}"),
300                ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
301            },
302            JsonErrorKind::ScanWithContext {
303                error,
304                expected_type,
305            } => match error {
306                ScanErrorKind::UnexpectedChar(c) => {
307                    format!("unexpected '{c}', expected {expected_type}")
308                }
309                ScanErrorKind::UnexpectedEof(_) => {
310                    format!("unexpected end of input, expected {expected_type}")
311                }
312                ScanErrorKind::InvalidUtf8 => "invalid UTF-8 here".into(),
313            },
314            JsonErrorKind::UnexpectedToken { got, expected } => {
315                format!("expected {expected}, got '{got}'")
316            }
317            JsonErrorKind::UnexpectedEof { expected } => format!("expected {expected}"),
318            JsonErrorKind::TypeMismatch { expected, got } => {
319                format!("expected {expected}, got {got}")
320            }
321            JsonErrorKind::UnknownField {
322                field, suggestion, ..
323            } => {
324                if let Some(suggested) = suggestion {
325                    format!("unknown field '{field}' - did you mean '{suggested}'?")
326                } else {
327                    format!("unknown field '{field}'")
328                }
329            }
330            JsonErrorKind::MissingField { field, .. } => format!("missing field '{field}'"),
331            JsonErrorKind::InvalidValue { .. } => "invalid value".into(),
332            JsonErrorKind::Reflect(_) => "reflection error".into(),
333            JsonErrorKind::NumberOutOfRange { target_type, .. } => {
334                format!("out of range for {target_type}")
335            }
336            JsonErrorKind::DuplicateKey { key } => format!("duplicate key '{key}'"),
337            JsonErrorKind::InvalidUtf8 => "invalid UTF-8".into(),
338            JsonErrorKind::Solver(_) => "solver error".into(),
339            JsonErrorKind::Io(_) => "I/O error".into(),
340        }
341    }
342}
343
344impl From<AdapterError> for JsonError {
345    fn from(err: AdapterError) -> Self {
346        let kind = match err.kind {
347            AdapterErrorKind::Scan(scan_err) => JsonErrorKind::Scan(scan_err),
348            AdapterErrorKind::NeedMore => JsonErrorKind::UnexpectedEof {
349                expected: "more data",
350            },
351        };
352        JsonError {
353            kind,
354            span: Some(err.span),
355            source_code: None,
356        }
357    }
358}
359
360impl From<ReflectError> for JsonError {
361    fn from(err: ReflectError) -> Self {
362        JsonError {
363            kind: JsonErrorKind::Reflect(err),
364            span: None,
365            source_code: None,
366        }
367    }
368}
369
370/// Result type for JSON deserialization
371pub type Result<T> = core::result::Result<T, JsonError>;
372
373// ============================================================================
374// Deserializer
375// ============================================================================
376
377use crate::adapter::TokenSource;
378
379/// JSON deserializer using recursive descent.
380///
381/// Generic over a token source `A` which must implement `TokenSource<'input>`.
382/// The const generic `BORROW` controls whether string data can be borrowed:
383/// - `BORROW=true`: strings without escapes are borrowed from input (for slice-based parsing)
384/// - `BORROW=false`: all strings are owned (for streaming or owned output)
385///
386/// For slice-based parsing, use `SliceAdapter<'input, BORROW>`.
387/// For streaming parsing, use `StreamingAdapter` with `BORROW=false`.
388pub struct JsonDeserializer<'input, const BORROW: bool, A: TokenSource<'input>> {
389    adapter: A,
390    /// Peeked token (for lookahead)
391    peeked: Option<SpannedAdapterToken<'input>>,
392}
393
394impl<'input> JsonDeserializer<'input, true, SliceAdapter<'input, true>> {
395    /// Create a new deserializer for the given input.
396    /// Strings without escapes will be borrowed from input.
397    pub fn new(input: &'input [u8]) -> Self {
398        JsonDeserializer {
399            adapter: SliceAdapter::new(input),
400            peeked: None,
401        }
402    }
403}
404
405impl<'input> JsonDeserializer<'input, false, SliceAdapter<'input, false>> {
406    /// Create a new deserializer that produces owned strings.
407    /// Use this when deserializing into owned types from temporary buffers.
408    pub fn new_owned(input: &'input [u8]) -> Self {
409        JsonDeserializer {
410            adapter: SliceAdapter::new(input),
411            peeked: None,
412        }
413    }
414}
415
416impl<'input, const BORROW: bool, A: TokenSource<'input>> JsonDeserializer<'input, BORROW, A> {
417    /// Create a deserializer from an existing adapter.
418    pub fn from_adapter(adapter: A) -> Self {
419        JsonDeserializer {
420            adapter,
421            peeked: None,
422        }
423    }
424
425    /// Peek at the next token without consuming it.
426    fn peek(&mut self) -> Result<&SpannedAdapterToken<'input>> {
427        if self.peeked.is_none() {
428            self.peeked = Some(self.adapter.next_token()?);
429        }
430        Ok(self.peeked.as_ref().unwrap())
431    }
432
433    /// Consume and return the next token.
434    fn next(&mut self) -> Result<SpannedAdapterToken<'input>> {
435        if let Some(token) = self.peeked.take() {
436            Ok(token)
437        } else {
438            Ok(self.adapter.next_token()?)
439        }
440    }
441
442    /// Consume the next token with type context for better error messages.
443    fn next_expecting(
444        &mut self,
445        expected_type: &'static str,
446    ) -> Result<SpannedAdapterToken<'input>> {
447        match self.next() {
448            Ok(token) => Ok(token),
449            Err(e) => {
450                // If it's a plain scan error, wrap it with context
451                if let JsonErrorKind::Scan(scan_err) = e.kind {
452                    Err(JsonError {
453                        kind: JsonErrorKind::ScanWithContext {
454                            error: scan_err,
455                            expected_type,
456                        },
457                        span: e.span,
458                        source_code: e.source_code,
459                    })
460                } else {
461                    Err(e)
462                }
463            }
464        }
465    }
466
467    /// Expect a specific token, consuming it.
468    #[allow(dead_code)]
469    fn expect(&mut self, _expected: &'static str) -> Result<SpannedAdapterToken<'input>> {
470        let token = self.next()?;
471        // For now, just return the token - caller validates
472        Ok(token)
473    }
474
475    /// Skip a JSON value (for unknown fields).
476    fn skip_value(&mut self) -> Result<Span> {
477        let token = self.next()?;
478        let start_span = token.span;
479
480        match token.token {
481            Token::ObjectStart => {
482                // Skip object
483                let mut depth = 1;
484                while depth > 0 {
485                    let t = self.next()?;
486                    match t.token {
487                        Token::ObjectStart => depth += 1,
488                        Token::ObjectEnd => depth -= 1,
489                        _ => {}
490                    }
491                }
492                Ok(start_span)
493            }
494            Token::ArrayStart => {
495                // Skip array
496                let mut depth = 1;
497                while depth > 0 {
498                    let t = self.next()?;
499                    match t.token {
500                        Token::ArrayStart => depth += 1,
501                        Token::ArrayEnd => depth -= 1,
502                        _ => {}
503                    }
504                }
505                Ok(start_span)
506            }
507            Token::String(_)
508            | Token::F64(_)
509            | Token::I64(_)
510            | Token::U64(_)
511            | Token::U128(_)
512            | Token::I128(_)
513            | Token::True
514            | Token::False
515            | Token::Null => Ok(start_span),
516            _ => Err(JsonError::new(
517                JsonErrorKind::UnexpectedToken {
518                    got: format!("{:?}", token.token),
519                    expected: "value",
520                },
521                token.span,
522            )),
523        }
524    }
525
526    /// Capture a raw JSON value as a string slice.
527    ///
528    /// This skips the value while tracking its full span, then returns
529    /// the raw JSON text.
530    ///
531    /// Note: This requires the adapter to provide input bytes (slice-based parsing).
532    /// For streaming adapters, this will return an error.
533    fn capture_raw_value(&mut self) -> Result<&'input str> {
534        // Check if we have access to input bytes
535        let input = self.adapter.input_bytes().ok_or_else(|| {
536            JsonError::without_span(JsonErrorKind::InvalidValue {
537                message: "RawJson capture is not supported in streaming mode".into(),
538            })
539        })?;
540
541        let token = self.next()?;
542        let start_offset = token.span.offset;
543
544        let end_offset = match token.token {
545            Token::ObjectStart => {
546                // Capture object
547                let mut depth = 1;
548                let mut last_span = token.span;
549                while depth > 0 {
550                    let t = self.next()?;
551                    last_span = t.span;
552                    match t.token {
553                        Token::ObjectStart => depth += 1,
554                        Token::ObjectEnd => depth -= 1,
555                        _ => {}
556                    }
557                }
558                last_span.offset + last_span.len
559            }
560            Token::ArrayStart => {
561                // Capture array
562                let mut depth = 1;
563                let mut last_span = token.span;
564                while depth > 0 {
565                    let t = self.next()?;
566                    last_span = t.span;
567                    match t.token {
568                        Token::ArrayStart => depth += 1,
569                        Token::ArrayEnd => depth -= 1,
570                        _ => {}
571                    }
572                }
573                last_span.offset + last_span.len
574            }
575            Token::String(_)
576            | Token::F64(_)
577            | Token::I64(_)
578            | Token::U64(_)
579            | Token::U128(_)
580            | Token::I128(_)
581            | Token::True
582            | Token::False
583            | Token::Null => token.span.offset + token.span.len,
584            _ => {
585                return Err(JsonError::new(
586                    JsonErrorKind::UnexpectedToken {
587                        got: format!("{:?}", token.token),
588                        expected: "value",
589                    },
590                    token.span,
591                ));
592            }
593        };
594
595        // Extract the raw bytes and convert to str
596        let raw_bytes = &input[start_offset..end_offset];
597        core::str::from_utf8(raw_bytes).map_err(|e| {
598            JsonError::without_span(JsonErrorKind::InvalidValue {
599                message: format!("invalid UTF-8 in raw JSON: {e}"),
600            })
601        })
602    }
603
604    /// Check if a struct has any flattened fields.
605    fn has_flatten_fields(struct_def: &facet_core::StructType) -> bool {
606        struct_def.fields.iter().any(|f| f.is_flattened())
607    }
608
609    /// Main deserialization entry point - deserialize into a Partial.
610    pub fn deserialize_into(
611        &mut self,
612        mut wip: Partial<'input, BORROW>,
613    ) -> Result<Partial<'input, BORROW>> {
614        let shape = wip.shape();
615        log::trace!(
616            "deserialize_into: shape={}, def={:?}",
617            shape.type_identifier,
618            std::mem::discriminant(&shape.def)
619        );
620
621        // Check for Spanned<T> wrapper first
622        if is_spanned_shape(shape) {
623            return self.deserialize_spanned(wip);
624        }
625
626        // Check for RawJson - capture raw bytes without parsing
627        if shape == RawJson::SHAPE {
628            let raw = self.capture_raw_value()?;
629            wip = wip.set(RawJson::new(raw))?;
630            return Ok(wip);
631        }
632
633        // Check for container-level proxy (applies to values inside Vec<T>, Option<T>, etc.)
634        #[cfg(feature = "alloc")]
635        {
636            let (wip_returned, has_proxy) = wip.begin_custom_deserialization_from_shape()?;
637            wip = wip_returned;
638            if has_proxy {
639                log::trace!(
640                    "deserialize_into: using container-level proxy for {}",
641                    shape.type_identifier
642                );
643                wip = self.deserialize_into(wip)?;
644                return wip.end().map_err(Into::into);
645            }
646        }
647
648        // Check Def first for Option (which is also a Type::User::Enum)
649        // Must come before the inner check since Option also has .inner() set
650        let is_option = matches!(&shape.def, Def::Option(_));
651        log::trace!("deserialize_into: is_option={is_option}");
652        if is_option {
653            return self.deserialize_option(wip);
654        }
655
656        // Priority 1: Check for builder_shape (immutable collections like Bytes -> BytesMut)
657        // These types need to build through a different type
658        if shape.builder_shape.is_some() {
659            wip = wip.begin_inner()?;
660            // Check if field has custom deserialization
661            if wip
662                .parent_field()
663                .and_then(|field| field.proxy_convert_in_fn())
664                .is_some()
665            {
666                wip = wip.begin_custom_deserialization()?;
667                wip = self.deserialize_into(wip)?;
668                wip = wip.end()?;
669            } else {
670                wip = self.deserialize_into(wip)?;
671            }
672            wip = wip.end()?;
673            return Ok(wip);
674        }
675
676        // Priority 2: Check for smart pointers (Box, Arc, Rc) before other Defs
677        if matches!(&shape.def, Def::Pointer(_)) {
678            return self.deserialize_pointer(wip);
679        }
680
681        // Priority 3: Check for .inner (transparent wrappers like NonZero)
682        // Collections (List/Map/Set/Array) have .inner for variance but shouldn't use this path
683        if shape.inner.is_some()
684            && !matches!(
685                &shape.def,
686                Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
687            )
688        {
689            wip = wip.begin_inner()?;
690            wip = self.deserialize_into(wip)?;
691            wip = wip.end()?;
692            return Ok(wip);
693        }
694
695        // Priority 4: Check the Type - structs and enums are identified by Type, not Def
696        match &shape.ty {
697            Type::User(UserType::Struct(struct_def)) => {
698                // Tuples and tuple structs both deserialize from JSON arrays.
699                if matches!(struct_def.kind, StructKind::Tuple | StructKind::TupleStruct) {
700                    return self.deserialize_tuple(wip);
701                }
702                return self.deserialize_struct(wip);
703            }
704            Type::User(UserType::Enum(_)) => return self.deserialize_enum(wip),
705            _ => {}
706        }
707
708        // Priority 5: Check Def for containers and special types
709        match &shape.def {
710            Def::Scalar => self.deserialize_scalar(wip),
711            Def::List(_) => self.deserialize_list(wip),
712            Def::Map(_) => self.deserialize_map(wip),
713            Def::Array(_) => self.deserialize_array(wip),
714            Def::Set(_) => self.deserialize_set(wip),
715            Def::DynamicValue(_) => self.deserialize_dynamic_value(wip),
716            _ => Err(JsonError::without_span(JsonErrorKind::InvalidValue {
717                message: format!("unsupported shape def: {:?}", shape.def),
718            })),
719        }
720    }
721
722    /// Deserialize into a type with span metadata (like `Spanned<T>`).
723    ///
724    /// This handles structs that have:
725    /// - One or more non-metadata fields (the actual values to deserialize)
726    /// - A field with `#[facet(metadata = span)]` to store source location
727    fn deserialize_spanned(
728        &mut self,
729        mut wip: Partial<'input, BORROW>,
730    ) -> Result<Partial<'input, BORROW>> {
731        log::trace!("deserialize_spanned");
732
733        let shape = wip.shape();
734
735        // Find the span metadata field and non-metadata fields
736        let Type::User(UserType::Struct(struct_def)) = &shape.ty else {
737            return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
738                message: format!(
739                    "expected struct with span metadata, found {}",
740                    shape.type_identifier
741                ),
742            }));
743        };
744
745        let span_field = struct_def
746            .fields
747            .iter()
748            .find(|f| f.metadata_kind() == Some("span"))
749            .ok_or_else(|| {
750                JsonError::without_span(JsonErrorKind::InvalidValue {
751                    message: format!(
752                        "expected struct with span metadata field, found {}",
753                        shape.type_identifier
754                    ),
755                })
756            })?;
757
758        let value_fields: Vec<_> = struct_def
759            .fields
760            .iter()
761            .filter(|f| !f.is_metadata())
762            .collect();
763
764        // Peek to get the span of the value we're about to parse
765        let value_span = self.peek()?.span;
766
767        // Deserialize all non-metadata fields
768        // For the common case (Spanned<T> with a single "value" field), this is just one field
769        for field in value_fields {
770            wip = wip.begin_field(field.name)?;
771            wip = self.deserialize_into(wip)?;
772            wip = wip.end()?;
773        }
774
775        // Set the span metadata field
776        // The span field should be of type Span with offset and len
777        wip = wip.begin_field(span_field.name)?;
778        wip = wip.set_field("offset", value_span.offset)?;
779        wip = wip.set_field("len", value_span.len)?;
780        wip = wip.end()?;
781
782        Ok(wip)
783    }
784
785    /// Deserialize a scalar value.
786    fn deserialize_scalar(
787        &mut self,
788        mut wip: Partial<'input, BORROW>,
789    ) -> Result<Partial<'input, BORROW>> {
790        let expected_type = wip.shape().type_identifier;
791        let token = self.next_expecting(expected_type)?;
792        log::trace!("deserialize_scalar: token={:?}", token.token);
793
794        match token.token {
795            Token::String(s) => {
796                // Try parse_from_str first if the type supports it (e.g., chrono types)
797                if wip.shape().vtable.has_parse() {
798                    wip = wip.parse_from_str(&s)?;
799                } else if wip.shape().type_identifier == "Cow" {
800                    // Zero-copy Cow<str>: preserve borrowed/owned status
801                    wip = wip.set(s)?;
802                } else {
803                    wip = wip.set(s.into_owned())?;
804                }
805            }
806            Token::True => {
807                wip = wip.set(true)?;
808            }
809            Token::False => {
810                wip = wip.set(false)?;
811            }
812            Token::Null => {
813                // For scalars, null typically means default
814                wip = wip.set_default()?;
815            }
816            Token::F64(n) => {
817                wip = self.set_number_f64(wip, n, token.span)?;
818            }
819            Token::I64(n) => {
820                wip = self.set_number_i64(wip, n, token.span)?;
821            }
822            Token::U64(n) => {
823                wip = self.set_number_u64(wip, n, token.span)?;
824            }
825            Token::I128(n) => {
826                wip = self.set_number_i128(wip, n, token.span)?;
827            }
828            Token::U128(n) => {
829                wip = self.set_number_u128(wip, n, token.span)?;
830            }
831            _ => {
832                return Err(JsonError::new(
833                    JsonErrorKind::UnexpectedToken {
834                        got: format!("{:?}", token.token),
835                        expected: "scalar value",
836                    },
837                    token.span,
838                ));
839            }
840        }
841        Ok(wip)
842    }
843
844    /// Deserialize any JSON value into a DynamicValue type.
845    ///
846    /// This handles all JSON value types: null, bool, number, string, array, and object.
847    fn deserialize_dynamic_value(
848        &mut self,
849        mut wip: Partial<'input, BORROW>,
850    ) -> Result<Partial<'input, BORROW>> {
851        let token = self.peek()?;
852        log::trace!("deserialize_dynamic_value: token={:?}", token.token);
853
854        match token.token {
855            Token::Null => {
856                self.next()?; // consume the token
857                wip = wip.set_default()?;
858            }
859            Token::True => {
860                self.next()?;
861                wip = wip.set(true)?;
862            }
863            Token::False => {
864                self.next()?;
865                wip = wip.set(false)?;
866            }
867            Token::I64(n) => {
868                self.next()?;
869                wip = wip.set(n)?;
870            }
871            Token::U64(n) => {
872                self.next()?;
873                // Store as i64 if it fits, otherwise as u64
874                if n <= i64::MAX as u64 {
875                    wip = wip.set(n as i64)?;
876                } else {
877                    wip = wip.set(n)?;
878                }
879            }
880            Token::F64(n) => {
881                self.next()?;
882                wip = wip.set(n)?;
883            }
884            Token::I128(n) => {
885                self.next()?;
886                // Try to fit in i64
887                if let Ok(n) = i64::try_from(n) {
888                    wip = wip.set(n)?;
889                } else {
890                    return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
891                        message: format!("i128 value {n} doesn't fit in dynamic value"),
892                    }));
893                }
894            }
895            Token::U128(n) => {
896                self.next()?;
897                // Try to fit in i64 or u64
898                if let Ok(n) = i64::try_from(n) {
899                    wip = wip.set(n)?;
900                } else if let Ok(n) = u64::try_from(n) {
901                    wip = wip.set(n)?;
902                } else {
903                    return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
904                        message: format!("u128 value {n} doesn't fit in dynamic value"),
905                    }));
906                }
907            }
908            Token::String(ref _s) => {
909                // Consume token and get owned string
910                let token = self.next()?;
911                if let Token::String(s) = token.token {
912                    wip = wip.set(s.into_owned())?;
913                }
914            }
915            Token::ArrayStart => {
916                self.next()?; // consume '['
917                wip = wip.begin_list()?;
918
919                loop {
920                    let token = self.peek()?;
921                    if matches!(token.token, Token::ArrayEnd) {
922                        self.next()?;
923                        break;
924                    }
925
926                    wip = wip.begin_list_item()?;
927                    wip = self.deserialize_dynamic_value(wip)?;
928                    wip = wip.end()?;
929
930                    let next = self.peek()?;
931                    if matches!(next.token, Token::Comma) {
932                        self.next()?;
933                    }
934                }
935            }
936            Token::ObjectStart => {
937                self.next()?; // consume '{'
938                wip = wip.begin_map()?; // Initialize as object
939
940                loop {
941                    let token = self.peek()?;
942                    if matches!(token.token, Token::ObjectEnd) {
943                        self.next()?;
944                        break;
945                    }
946
947                    // Parse key (must be a string)
948                    let key_token = self.next()?;
949                    let key = match key_token.token {
950                        Token::String(s) => s.into_owned(),
951                        _ => {
952                            return Err(JsonError::new(
953                                JsonErrorKind::UnexpectedToken {
954                                    got: format!("{:?}", key_token.token),
955                                    expected: "string key",
956                                },
957                                key_token.span,
958                            ));
959                        }
960                    };
961
962                    // Expect colon
963                    let colon = self.next()?;
964                    if !matches!(colon.token, Token::Colon) {
965                        return Err(JsonError::new(
966                            JsonErrorKind::UnexpectedToken {
967                                got: format!("{:?}", colon.token),
968                                expected: "':'",
969                            },
970                            colon.span,
971                        ));
972                    }
973
974                    // Start object entry and deserialize value
975                    wip = wip.begin_object_entry(&key)?;
976                    wip = self.deserialize_dynamic_value(wip)?;
977                    wip = wip.end()?;
978
979                    // Check for comma or end
980                    let next = self.peek()?;
981                    if matches!(next.token, Token::Comma) {
982                        self.next()?;
983                    }
984                }
985            }
986            _ => {
987                return Err(JsonError::new(
988                    JsonErrorKind::UnexpectedToken {
989                        got: format!("{:?}", token.token),
990                        expected: "any JSON value",
991                    },
992                    token.span,
993                ));
994            }
995        }
996        Ok(wip)
997    }
998
999    /// Set a string value, handling `&str`, `Cow<str>`, and `String` appropriately.
1000    fn set_string_value(
1001        &mut self,
1002        mut wip: Partial<'input, BORROW>,
1003        s: Cow<'input, str>,
1004    ) -> Result<Partial<'input, BORROW>> {
1005        let shape = wip.shape();
1006
1007        // Check if target is &str (shared reference to str)
1008        if let Def::Pointer(ptr_def) = shape.def
1009            && matches!(ptr_def.known, Some(KnownPointer::SharedReference))
1010            && ptr_def
1011                .pointee()
1012                .is_some_and(|p| p.type_identifier == "str")
1013        {
1014            // In owned mode, we cannot borrow from input at all
1015            if !BORROW {
1016                return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
1017                    message: "cannot deserialize into &str when borrowing is disabled - use String or Cow<str> instead".into(),
1018                }));
1019            }
1020            match s {
1021                Cow::Borrowed(borrowed) => {
1022                    wip = wip.set(borrowed)?;
1023                    return Ok(wip);
1024                }
1025                Cow::Owned(_) => {
1026                    return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
1027                        message: "cannot borrow &str from JSON string containing escape sequences - use String instead".into(),
1028                    }));
1029                }
1030            }
1031        }
1032
1033        // Check if target is Cow<str>
1034        if let Def::Pointer(ptr_def) = shape.def
1035            && matches!(ptr_def.known, Some(KnownPointer::Cow))
1036            && ptr_def
1037                .pointee()
1038                .is_some_and(|p| p.type_identifier == "str")
1039        {
1040            wip = wip.set(s)?;
1041            return Ok(wip);
1042        }
1043
1044        // Default: convert to owned String
1045        wip = wip.set(s.into_owned())?;
1046        Ok(wip)
1047    }
1048
1049    /// Deserialize a map key from a JSON string.
1050    ///
1051    /// JSON only allows string keys, but the target map might have non-string key types
1052    /// (e.g., integers, enums). This function parses the string key into the appropriate type:
1053    /// - String types: set directly
1054    /// - Enum unit variants: use select_variant_named
1055    /// - Integer types: parse the string as a number
1056    /// - Transparent newtypes: descend into the inner type
1057    fn deserialize_map_key(
1058        &mut self,
1059        mut wip: Partial<'input, BORROW>,
1060        key: Cow<'input, str>,
1061        span: Span,
1062    ) -> Result<Partial<'input, BORROW>> {
1063        let shape = wip.shape();
1064
1065        // For transparent types (like UserId(String)), we need to use begin_inner
1066        // to set the inner value. But NOT for pointer types like &str or Cow<str>
1067        // which are handled directly.
1068        let is_pointer = matches!(shape.def, Def::Pointer(_));
1069        if shape.inner.is_some() && !is_pointer {
1070            wip = wip.begin_inner()?;
1071            wip = self.deserialize_map_key(wip, key, span)?;
1072            wip = wip.end()?;
1073            return Ok(wip);
1074        }
1075
1076        // Check if target is an enum - use select_variant_named for unit variants
1077        if let Type::User(UserType::Enum(_)) = &shape.ty {
1078            wip = wip.select_variant_named(&key)?;
1079            return Ok(wip);
1080        }
1081
1082        // Check if target is a numeric type - parse the string key as a number
1083        if let Type::Primitive(PrimitiveType::Numeric(num_ty)) = &shape.ty {
1084            match num_ty {
1085                NumericType::Integer { signed } => {
1086                    if *signed {
1087                        let n: i64 = key.parse().map_err(|_| {
1088                            JsonError::new(
1089                                JsonErrorKind::InvalidValue {
1090                                    message: format!(
1091                                        "cannot parse '{}' as integer for map key",
1092                                        key
1093                                    ),
1094                                },
1095                                span,
1096                            )
1097                        })?;
1098                        wip = self.set_number_i64(wip, n, span)?;
1099                    } else {
1100                        let n: u64 = key.parse().map_err(|_| {
1101                            JsonError::new(
1102                                JsonErrorKind::InvalidValue {
1103                                    message: format!(
1104                                        "cannot parse '{}' as unsigned integer for map key",
1105                                        key
1106                                    ),
1107                                },
1108                                span,
1109                            )
1110                        })?;
1111                        wip = self.set_number_u64(wip, n, span)?;
1112                    }
1113                    return Ok(wip);
1114                }
1115                NumericType::Float => {
1116                    let n: f64 = key.parse().map_err(|_| {
1117                        JsonError::new(
1118                            JsonErrorKind::InvalidValue {
1119                                message: format!("cannot parse '{}' as float for map key", key),
1120                            },
1121                            span,
1122                        )
1123                    })?;
1124                    wip = self.set_number_f64(wip, n, span)?;
1125                    return Ok(wip);
1126                }
1127            }
1128        }
1129
1130        // Default: treat as string
1131        wip = self.set_string_value(wip, key)?;
1132        Ok(wip)
1133    }
1134
1135    /// Set a numeric value, handling type conversions.
1136    fn set_number_f64(
1137        &mut self,
1138        mut wip: Partial<'input, BORROW>,
1139        n: f64,
1140        span: Span,
1141    ) -> Result<Partial<'input, BORROW>> {
1142        let shape = wip.shape();
1143        let ty = match &shape.ty {
1144            Type::Primitive(PrimitiveType::Numeric(ty)) => ty,
1145            _ => {
1146                return Err(JsonError::new(
1147                    JsonErrorKind::TypeMismatch {
1148                        expected: shape.type_identifier,
1149                        got: "number",
1150                    },
1151                    span,
1152                ));
1153            }
1154        };
1155
1156        match ty {
1157            NumericType::Float => {
1158                let size = match shape.layout {
1159                    ShapeLayout::Sized(layout) => layout.size(),
1160                    _ => {
1161                        return Err(JsonError::new(
1162                            JsonErrorKind::InvalidValue {
1163                                message: "unsized float".into(),
1164                            },
1165                            span,
1166                        ));
1167                    }
1168                };
1169                match size {
1170                    4 => {
1171                        wip = wip.set(n as f32)?;
1172                    }
1173                    8 => {
1174                        wip = wip.set(n)?;
1175                    }
1176                    _ => {
1177                        return Err(JsonError::new(
1178                            JsonErrorKind::InvalidValue {
1179                                message: format!("unexpected float size: {size}"),
1180                            },
1181                            span,
1182                        ));
1183                    }
1184                }
1185            }
1186            NumericType::Integer { signed } => {
1187                // Try to convert float to integer
1188                if n.fract() != 0.0 {
1189                    return Err(JsonError::new(
1190                        JsonErrorKind::TypeMismatch {
1191                            expected: shape.type_identifier,
1192                            got: "float with fractional part",
1193                        },
1194                        span,
1195                    ));
1196                }
1197                if *signed {
1198                    wip = self.set_number_i64(wip, n as i64, span)?;
1199                } else {
1200                    wip = self.set_number_u64(wip, n as u64, span)?;
1201                }
1202            }
1203        }
1204        Ok(wip)
1205    }
1206
1207    fn set_number_i64(
1208        &mut self,
1209        mut wip: Partial<'input, BORROW>,
1210        n: i64,
1211        span: Span,
1212    ) -> Result<Partial<'input, BORROW>> {
1213        let shape = wip.shape();
1214        let size = match shape.layout {
1215            ShapeLayout::Sized(layout) => layout.size(),
1216            _ => {
1217                return Err(JsonError::new(
1218                    JsonErrorKind::InvalidValue {
1219                        message: "unsized integer".into(),
1220                    },
1221                    span,
1222                ));
1223            }
1224        };
1225
1226        // Check type and convert
1227        match &shape.ty {
1228            Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: true })) => {
1229                match size {
1230                    1 => {
1231                        let v = i8::try_from(n).map_err(|_| {
1232                            JsonError::new(
1233                                JsonErrorKind::NumberOutOfRange {
1234                                    value: n.to_string(),
1235                                    target_type: "i8",
1236                                },
1237                                span,
1238                            )
1239                        })?;
1240                        wip = wip.set(v)?;
1241                    }
1242                    2 => {
1243                        let v = i16::try_from(n).map_err(|_| {
1244                            JsonError::new(
1245                                JsonErrorKind::NumberOutOfRange {
1246                                    value: n.to_string(),
1247                                    target_type: "i16",
1248                                },
1249                                span,
1250                            )
1251                        })?;
1252                        wip = wip.set(v)?;
1253                    }
1254                    4 => {
1255                        let v = i32::try_from(n).map_err(|_| {
1256                            JsonError::new(
1257                                JsonErrorKind::NumberOutOfRange {
1258                                    value: n.to_string(),
1259                                    target_type: "i32",
1260                                },
1261                                span,
1262                            )
1263                        })?;
1264                        wip = wip.set(v)?;
1265                    }
1266                    8 => {
1267                        // Check if the target is isize (which has size 8 on 64-bit)
1268                        if shape.scalar_type() == Some(ScalarType::ISize) {
1269                            let v = isize::try_from(n).map_err(|_| {
1270                                JsonError::new(
1271                                    JsonErrorKind::NumberOutOfRange {
1272                                        value: n.to_string(),
1273                                        target_type: "isize",
1274                                    },
1275                                    span,
1276                                )
1277                            })?;
1278                            wip = wip.set(v)?;
1279                        } else {
1280                            wip = wip.set(n)?;
1281                        }
1282                    }
1283                    16 => {
1284                        wip = wip.set(n as i128)?;
1285                    }
1286                    _ => {
1287                        // Handle isize on 32-bit platforms (size 4)
1288                        if shape.scalar_type() == Some(ScalarType::ISize) {
1289                            let v = isize::try_from(n).map_err(|_| {
1290                                JsonError::new(
1291                                    JsonErrorKind::NumberOutOfRange {
1292                                        value: n.to_string(),
1293                                        target_type: "isize",
1294                                    },
1295                                    span,
1296                                )
1297                            })?;
1298                            wip = wip.set(v)?;
1299                        } else {
1300                            return Err(JsonError::new(
1301                                JsonErrorKind::InvalidValue {
1302                                    message: format!("unexpected integer size: {size}"),
1303                                },
1304                                span,
1305                            ));
1306                        }
1307                    }
1308                }
1309            }
1310            Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: false })) => {
1311                if n < 0 {
1312                    return Err(JsonError::new(
1313                        JsonErrorKind::NumberOutOfRange {
1314                            value: n.to_string(),
1315                            target_type: shape.type_identifier,
1316                        },
1317                        span,
1318                    ));
1319                }
1320                wip = self.set_number_u64(wip, n as u64, span)?;
1321            }
1322            Type::Primitive(PrimitiveType::Numeric(NumericType::Float)) => match size {
1323                4 => {
1324                    wip = wip.set(n as f32)?;
1325                }
1326                8 => {
1327                    wip = wip.set(n as f64)?;
1328                }
1329                _ => {
1330                    return Err(JsonError::new(
1331                        JsonErrorKind::InvalidValue {
1332                            message: format!("unexpected float size: {size}"),
1333                        },
1334                        span,
1335                    ));
1336                }
1337            },
1338            _ => {
1339                return Err(JsonError::new(
1340                    JsonErrorKind::TypeMismatch {
1341                        expected: shape.type_identifier,
1342                        got: "integer",
1343                    },
1344                    span,
1345                ));
1346            }
1347        }
1348        Ok(wip)
1349    }
1350
1351    fn set_number_u64(
1352        &mut self,
1353        mut wip: Partial<'input, BORROW>,
1354        n: u64,
1355        span: Span,
1356    ) -> Result<Partial<'input, BORROW>> {
1357        let shape = wip.shape();
1358        let size = match shape.layout {
1359            ShapeLayout::Sized(layout) => layout.size(),
1360            _ => {
1361                return Err(JsonError::new(
1362                    JsonErrorKind::InvalidValue {
1363                        message: "unsized integer".into(),
1364                    },
1365                    span,
1366                ));
1367            }
1368        };
1369
1370        match &shape.ty {
1371            Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: false })) => {
1372                match size {
1373                    1 => {
1374                        let v = u8::try_from(n).map_err(|_| {
1375                            JsonError::new(
1376                                JsonErrorKind::NumberOutOfRange {
1377                                    value: n.to_string(),
1378                                    target_type: "u8",
1379                                },
1380                                span,
1381                            )
1382                        })?;
1383                        wip = wip.set(v)?;
1384                    }
1385                    2 => {
1386                        let v = u16::try_from(n).map_err(|_| {
1387                            JsonError::new(
1388                                JsonErrorKind::NumberOutOfRange {
1389                                    value: n.to_string(),
1390                                    target_type: "u16",
1391                                },
1392                                span,
1393                            )
1394                        })?;
1395                        wip = wip.set(v)?;
1396                    }
1397                    4 => {
1398                        let v = u32::try_from(n).map_err(|_| {
1399                            JsonError::new(
1400                                JsonErrorKind::NumberOutOfRange {
1401                                    value: n.to_string(),
1402                                    target_type: "u32",
1403                                },
1404                                span,
1405                            )
1406                        })?;
1407                        wip = wip.set(v)?;
1408                    }
1409                    8 => {
1410                        // Check if the target is usize (which has size 8 on 64-bit)
1411                        if shape.scalar_type() == Some(ScalarType::USize) {
1412                            let v = usize::try_from(n).map_err(|_| {
1413                                JsonError::new(
1414                                    JsonErrorKind::NumberOutOfRange {
1415                                        value: n.to_string(),
1416                                        target_type: "usize",
1417                                    },
1418                                    span,
1419                                )
1420                            })?;
1421                            wip = wip.set(v)?;
1422                        } else {
1423                            wip = wip.set(n)?;
1424                        }
1425                    }
1426                    16 => {
1427                        wip = wip.set(n as u128)?;
1428                    }
1429                    _ => {
1430                        // Handle usize on 32-bit platforms (size 4)
1431                        if shape.scalar_type() == Some(ScalarType::USize) {
1432                            let v = usize::try_from(n).map_err(|_| {
1433                                JsonError::new(
1434                                    JsonErrorKind::NumberOutOfRange {
1435                                        value: n.to_string(),
1436                                        target_type: "usize",
1437                                    },
1438                                    span,
1439                                )
1440                            })?;
1441                            wip = wip.set(v)?;
1442                        } else {
1443                            return Err(JsonError::new(
1444                                JsonErrorKind::InvalidValue {
1445                                    message: format!("unexpected integer size: {size}"),
1446                                },
1447                                span,
1448                            ));
1449                        }
1450                    }
1451                }
1452            }
1453            Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: true })) => {
1454                // Convert unsigned to signed if it fits
1455                wip = self.set_number_i64(wip, n as i64, span)?;
1456            }
1457            Type::Primitive(PrimitiveType::Numeric(NumericType::Float)) => match size {
1458                4 => {
1459                    wip = wip.set(n as f32)?;
1460                }
1461                8 => {
1462                    wip = wip.set(n as f64)?;
1463                }
1464                _ => {
1465                    return Err(JsonError::new(
1466                        JsonErrorKind::InvalidValue {
1467                            message: format!("unexpected float size: {size}"),
1468                        },
1469                        span,
1470                    ));
1471                }
1472            },
1473            _ => {
1474                return Err(JsonError::new(
1475                    JsonErrorKind::TypeMismatch {
1476                        expected: shape.type_identifier,
1477                        got: "unsigned integer",
1478                    },
1479                    span,
1480                ));
1481            }
1482        }
1483        Ok(wip)
1484    }
1485
1486    fn set_number_i128(
1487        &mut self,
1488        mut wip: Partial<'input, BORROW>,
1489        n: i128,
1490        span: Span,
1491    ) -> Result<Partial<'input, BORROW>> {
1492        let shape = wip.shape();
1493        let size = match shape.layout {
1494            ShapeLayout::Sized(layout) => layout.size(),
1495            _ => {
1496                return Err(JsonError::new(
1497                    JsonErrorKind::InvalidValue {
1498                        message: "unsized integer".into(),
1499                    },
1500                    span,
1501                ));
1502            }
1503        };
1504
1505        if size == 16 {
1506            wip = wip.set(n)?;
1507        } else {
1508            // Try to fit in smaller type
1509            if let Ok(n64) = i64::try_from(n) {
1510                wip = self.set_number_i64(wip, n64, span)?;
1511            } else {
1512                return Err(JsonError::new(
1513                    JsonErrorKind::NumberOutOfRange {
1514                        value: n.to_string(),
1515                        target_type: shape.type_identifier,
1516                    },
1517                    span,
1518                ));
1519            }
1520        }
1521        Ok(wip)
1522    }
1523
1524    fn set_number_u128(
1525        &mut self,
1526        mut wip: Partial<'input, BORROW>,
1527        n: u128,
1528        span: Span,
1529    ) -> Result<Partial<'input, BORROW>> {
1530        let shape = wip.shape();
1531        let size = match shape.layout {
1532            ShapeLayout::Sized(layout) => layout.size(),
1533            _ => {
1534                return Err(JsonError::new(
1535                    JsonErrorKind::InvalidValue {
1536                        message: "unsized integer".into(),
1537                    },
1538                    span,
1539                ));
1540            }
1541        };
1542
1543        if size == 16 {
1544            wip = wip.set(n)?;
1545        } else {
1546            // Try to fit in smaller type
1547            if let Ok(n64) = u64::try_from(n) {
1548                wip = self.set_number_u64(wip, n64, span)?;
1549            } else {
1550                return Err(JsonError::new(
1551                    JsonErrorKind::NumberOutOfRange {
1552                        value: n.to_string(),
1553                        target_type: shape.type_identifier,
1554                    },
1555                    span,
1556                ));
1557            }
1558        }
1559        Ok(wip)
1560    }
1561
1562    /// Deserialize a struct from a JSON object.
1563    fn deserialize_struct(
1564        &mut self,
1565        wip: Partial<'input, BORROW>,
1566    ) -> Result<Partial<'input, BORROW>> {
1567        log::trace!("deserialize_struct: {}", wip.shape().type_identifier);
1568
1569        // Get struct fields to check for flatten
1570        let struct_def = match &wip.shape().ty {
1571            Type::User(UserType::Struct(s)) => s,
1572            _ => {
1573                return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
1574                    message: "expected struct type".into(),
1575                }));
1576            }
1577        };
1578
1579        // Check if this struct has any flattened fields - if so, use the solver
1580        if Self::has_flatten_fields(struct_def) {
1581            return self.deserialize_struct_with_flatten(wip);
1582        }
1583
1584        // Simple path: no flattened fields
1585        self.deserialize_struct_simple(wip)
1586    }
1587
1588    /// Deserialize a struct without flattened fields (simple case).
1589    fn deserialize_struct_simple(
1590        &mut self,
1591        mut wip: Partial<'input, BORROW>,
1592    ) -> Result<Partial<'input, BORROW>> {
1593        // Expect opening brace and track its span
1594        let open_token = self.next()?;
1595        let object_start_span = match open_token.token {
1596            Token::ObjectStart => open_token.span,
1597            _ => {
1598                return Err(JsonError::new(
1599                    JsonErrorKind::UnexpectedToken {
1600                        got: format!("{:?}", open_token.token),
1601                        expected: "'{'",
1602                    },
1603                    open_token.span,
1604                ));
1605            }
1606        };
1607
1608        // Get struct fields
1609        let struct_def = match &wip.shape().ty {
1610            Type::User(UserType::Struct(s)) => s,
1611            _ => {
1612                return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
1613                    message: "expected struct type".into(),
1614                }));
1615            }
1616        };
1617
1618        // Track which fields have been set
1619        let num_fields = struct_def.fields.len();
1620        let mut fields_set = alloc::vec![false; num_fields];
1621
1622        // Track the end of the object for error reporting
1623        #[allow(unused_assignments)]
1624        let mut object_end_span: Option<Span> = None;
1625
1626        // Check if the struct has a default attribute (all missing fields use defaults)
1627        let struct_has_default = wip.shape().has_default_attr();
1628        // Check if the struct denies unknown fields
1629        let deny_unknown_fields = wip.shape().has_deny_unknown_fields_attr();
1630
1631        // Parse fields until closing brace
1632        loop {
1633            let token = self.peek()?;
1634            match &token.token {
1635                Token::ObjectEnd => {
1636                    let close_token = self.next()?; // consume the brace
1637                    object_end_span = Some(close_token.span);
1638                    break;
1639                }
1640                Token::String(_) => {
1641                    // Parse field name
1642                    let key_token = self.next()?;
1643                    let key = match key_token.token {
1644                        Token::String(s) => s,
1645                        _ => unreachable!(),
1646                    };
1647                    let _key_span = key_token.span;
1648
1649                    // Expect colon
1650                    let colon = self.next()?;
1651                    if !matches!(colon.token, Token::Colon) {
1652                        return Err(JsonError::new(
1653                            JsonErrorKind::UnexpectedToken {
1654                                got: format!("{:?}", colon.token),
1655                                expected: "':'",
1656                            },
1657                            colon.span,
1658                        ));
1659                    }
1660
1661                    // Find the field by name and index
1662                    let field_info = struct_def
1663                        .fields
1664                        .iter()
1665                        .enumerate()
1666                        .find(|(_, f)| f.name == key.as_ref());
1667
1668                    if let Some((idx, field)) = field_info {
1669                        wip = wip.begin_field(field.name)?;
1670                        // Check if field has custom deserialization
1671                        if field.proxy_convert_in_fn().is_some() {
1672                            wip = wip.begin_custom_deserialization()?;
1673                            wip = self.deserialize_into(wip)?;
1674                            wip = wip.end()?; // Calls deserialize_with function
1675                        } else {
1676                            wip = self.deserialize_into(wip)?;
1677                        }
1678                        wip = wip.end()?;
1679                        fields_set[idx] = true;
1680                    } else {
1681                        // Unknown field
1682                        if deny_unknown_fields {
1683                            let expected_fields: Vec<&'static str> =
1684                                struct_def.fields.iter().map(|f| f.name).collect();
1685                            let suggestion = find_similar_field(&key, &expected_fields);
1686                            return Err(JsonError::new(
1687                                JsonErrorKind::UnknownField {
1688                                    field: key.into_owned(),
1689                                    expected: expected_fields,
1690                                    suggestion,
1691                                },
1692                                _key_span,
1693                            ));
1694                        }
1695                        log::trace!("skipping unknown field: {key}");
1696                        self.skip_value()?;
1697                    }
1698
1699                    // Check for comma or end
1700                    let next = self.peek()?;
1701                    if matches!(next.token, Token::Comma) {
1702                        self.next()?; // consume comma
1703                    }
1704                }
1705                _ => {
1706                    let span = token.span;
1707                    return Err(JsonError::new(
1708                        JsonErrorKind::UnexpectedToken {
1709                            got: format!("{:?}", token.token),
1710                            expected: "field name or '}'",
1711                        },
1712                        span,
1713                    ));
1714                }
1715            }
1716        }
1717
1718        // Apply defaults for missing fields and detect required but missing fields
1719        for (idx, field) in struct_def.fields.iter().enumerate() {
1720            if fields_set[idx] {
1721                continue; // Field was already set from JSON
1722            }
1723
1724            // Check if the field has a default available:
1725            // 1. Field has #[facet(default)] or #[facet(default = expr)]
1726            // 2. Struct has #[facet(default)] and field type implements Default
1727            let field_has_default = field.has_default();
1728            let field_type_has_default = field.shape().is(Characteristic::Default);
1729            let field_is_option = matches!(field.shape().def, Def::Option(_));
1730
1731            if field_has_default {
1732                // Use set_nth_field_to_default which handles both default_fn and Default impl
1733                wip = wip.set_nth_field_to_default(idx)?;
1734            } else if struct_has_default && field_type_has_default {
1735                // Struct-level #[facet(default)] - use the field type's Default
1736                wip = wip.set_nth_field_to_default(idx)?;
1737            } else if field_is_option {
1738                // Option<T> fields should default to None even without struct-level defaults
1739                wip = wip.begin_field(field.name)?;
1740                wip = wip.set_default()?;
1741                wip = wip.end()?;
1742            } else {
1743                // Required field is missing - raise our own error with spans
1744                return Err(JsonError {
1745                    kind: JsonErrorKind::MissingField {
1746                        field: field.name,
1747                        object_start: Some(object_start_span),
1748                        object_end: object_end_span,
1749                    },
1750                    span: None, // We use custom labels instead
1751                    source_code: None,
1752                });
1753            }
1754        }
1755
1756        Ok(wip)
1757    }
1758
1759    /// Deserialize a struct with flattened fields using facet-solver.
1760    ///
1761    /// This uses a two-pass approach:
1762    /// 1. Peek mode: Scan all keys, feed to solver, record value positions
1763    /// 2. Deserialize: Use the resolved Configuration to deserialize with proper path handling
1764    fn deserialize_struct_with_flatten(
1765        &mut self,
1766        mut wip: Partial<'input, BORROW>,
1767    ) -> Result<Partial<'input, BORROW>> {
1768        log::trace!(
1769            "deserialize_struct_with_flatten: {wip}",
1770            wip = wip.shape().type_identifier
1771        );
1772
1773        // Build the schema for this type with auto-detection of enum representations
1774        // This respects #[facet(tag = "...", content = "...")] and #[facet(untagged)] attributes
1775        let schema = Schema::build_auto(wip.shape()).map_err(|e| {
1776            JsonError::without_span(JsonErrorKind::Solver(format!(
1777                "failed to build schema: {e}"
1778            )))
1779        })?;
1780
1781        // Create the solver
1782        let mut solver = Solver::new(&schema);
1783
1784        // Track where values start so we can re-read them in pass 2
1785        let mut field_positions: Vec<(Cow<'input, str>, usize)> = Vec::new();
1786
1787        // Expect opening brace
1788        let token = self.next()?;
1789        match token.token {
1790            Token::ObjectStart => {}
1791            _ => {
1792                return Err(JsonError::new(
1793                    JsonErrorKind::UnexpectedToken {
1794                        got: format!("{:?}", token.token),
1795                        expected: "'{'",
1796                    },
1797                    token.span,
1798                ));
1799            }
1800        }
1801
1802        // ========== PASS 1: Peek mode - scan all keys, feed to solver ==========
1803        loop {
1804            let token = self.peek()?;
1805            match &token.token {
1806                Token::ObjectEnd => {
1807                    self.next()?; // consume the brace
1808                    break;
1809                }
1810                Token::String(_) => {
1811                    // Parse field name
1812                    let key_token = self.next()?;
1813                    let key = match &key_token.token {
1814                        Token::String(s) => s.clone(),
1815                        _ => unreachable!(),
1816                    };
1817
1818                    // Expect colon
1819                    let colon = self.next()?;
1820                    if !matches!(colon.token, Token::Colon) {
1821                        return Err(JsonError::new(
1822                            JsonErrorKind::UnexpectedToken {
1823                                got: format!("{:?}", colon.token),
1824                                expected: "':'",
1825                            },
1826                            colon.span,
1827                        ));
1828                    }
1829
1830                    // Record the value position before skipping
1831                    let value_start = self.peek()?.span.offset;
1832
1833                    // Feed key to solver (decision not used in peek mode)
1834                    let _decision = solver.see_key(key.clone());
1835
1836                    field_positions.push((key, value_start));
1837
1838                    // Skip the value
1839                    self.skip_value()?;
1840
1841                    // Check for comma
1842                    let next = self.peek()?;
1843                    if matches!(next.token, Token::Comma) {
1844                        self.next()?;
1845                    }
1846                }
1847                _ => {
1848                    let span = token.span;
1849                    return Err(JsonError::new(
1850                        JsonErrorKind::UnexpectedToken {
1851                            got: format!("{:?}", token.token),
1852                            expected: "field name or '}'",
1853                        },
1854                        span,
1855                    ));
1856                }
1857            }
1858        }
1859
1860        // ========== Get the resolved Configuration ==========
1861        // Get seen keys before finish() consumes the solver
1862        let seen_keys = solver.seen_keys().clone();
1863        let config_handle = solver
1864            .finish()
1865            .map_err(|e| JsonError::without_span(JsonErrorKind::Solver(format!("{e}"))))?;
1866        let config = config_handle.resolution();
1867
1868        // ========== PASS 2: Deserialize with proper path handling ==========
1869        // Sort fields by path depth (deepest first within each prefix group)
1870        // This ensures we set all fields at a given nesting level before closing it
1871        let mut fields_to_process: Vec<_> = field_positions
1872            .iter()
1873            .filter_map(|(key, offset)| config.field(key.as_ref()).map(|info| (info, *offset)))
1874            .collect();
1875
1876        // Sort by path to group nested fields together
1877        // We want to process in an order that allows proper begin/end management
1878        fields_to_process.sort_by(|(a, _), (b, _)| a.path.segments().cmp(b.path.segments()));
1879
1880        // Determine which optional fields are missing before PASS 2
1881        let missing_optional_fields: Vec<&FieldInfo> =
1882            config.missing_optional_fields(&seen_keys).collect();
1883
1884        let mut defaults_by_first_segment: BTreeMap<&str, Vec<&FieldInfo>> = BTreeMap::new();
1885        for info in &missing_optional_fields {
1886            if let Some(PathSegment::Field(name)) = info.path.segments().first() {
1887                defaults_by_first_segment
1888                    .entry(name)
1889                    .or_default()
1890                    .push(*info);
1891            }
1892        }
1893
1894        let processed_first_segments: BTreeSet<&str> = fields_to_process
1895            .iter()
1896            .filter_map(|(info, _)| {
1897                if let Some(PathSegment::Field(name)) = info.path.segments().first() {
1898                    Some(*name)
1899                } else {
1900                    None
1901                }
1902            })
1903            .collect();
1904
1905        let missing_first_segments: BTreeSet<&str> =
1906            defaults_by_first_segment.keys().copied().collect();
1907
1908        for first_field in &missing_first_segments {
1909            if processed_first_segments.contains(first_field) {
1910                continue;
1911            }
1912
1913            wip = wip.begin_field(first_field)?;
1914            if matches!(wip.shape().def, Def::Option(_)) {
1915                wip = wip.set_default()?;
1916                defaults_by_first_segment.remove(first_field);
1917            }
1918            wip = wip.end()?;
1919        }
1920
1921        // Track currently open path segments: (field_name, is_option)
1922        let mut open_segments: Vec<(&str, bool)> = Vec::new();
1923
1924        for (field_info, offset) in &fields_to_process {
1925            let segments = field_info.path.segments();
1926            let offset = *offset;
1927
1928            // Extract just the field names from the path (ignoring Variant segments for now)
1929            let field_segments: Vec<&str> = segments
1930                .iter()
1931                .filter_map(|s| match s {
1932                    PathSegment::Field(name) => Some(*name),
1933                    PathSegment::Variant(_, _) => None,
1934                })
1935                .collect();
1936
1937            // Find common prefix with currently open segments
1938            let common_len = open_segments
1939                .iter()
1940                .zip(field_segments.iter())
1941                .take_while(|((name, _), b)| *name == **b)
1942                .count();
1943
1944            // Close segments that are no longer needed (in reverse order)
1945            while open_segments.len() > common_len {
1946                let (segment_name, is_option) = open_segments.pop().unwrap();
1947                wip = self.apply_defaults_for_segment(
1948                    wip,
1949                    segment_name,
1950                    &mut defaults_by_first_segment,
1951                )?;
1952                if is_option {
1953                    wip = wip.end()?; // End the inner Some value
1954                }
1955                wip = wip.end()?; // End the field
1956            }
1957
1958            // Open new segments
1959            for &segment in &field_segments[common_len..] {
1960                wip = wip.begin_field(segment)?;
1961                // Check if we just entered an Option field - if so, initialize it as Some
1962                let is_option = matches!(wip.shape().def, Def::Option(_));
1963                if is_option {
1964                    wip = wip.begin_some()?;
1965                }
1966                open_segments.push((segment, is_option));
1967            }
1968
1969            // Handle variant selection if the path ends with a Variant segment
1970            let ends_with_variant = segments
1971                .last()
1972                .is_some_and(|s| matches!(s, PathSegment::Variant(_, _)));
1973
1974            if ends_with_variant
1975                && let Some(PathSegment::Variant(_, variant_name)) = segments.last()
1976            {
1977                wip = wip.select_variant_named(variant_name)?;
1978            }
1979
1980            // Create sub-deserializer and deserialize the value
1981            // Note: This requires the adapter to support at_offset (slice-based parsing).
1982            // For streaming adapters, flatten is not supported.
1983            let sub_adapter = self.adapter.at_offset(offset).ok_or_else(|| {
1984                JsonError::without_span(JsonErrorKind::InvalidValue {
1985                    message: "flatten is not supported in streaming mode".into(),
1986                })
1987            })?;
1988            let mut sub = Self::from_adapter(sub_adapter);
1989
1990            if ends_with_variant {
1991                wip = sub.deserialize_variant_struct_content(wip)?;
1992            } else {
1993                // Pop the last segment since we're about to deserialize into it
1994                // The deserialize_into will set the value directly
1995                if !open_segments.is_empty() {
1996                    let (segment_name, is_option) = open_segments.pop().unwrap();
1997                    wip = self.apply_defaults_for_segment(
1998                        wip,
1999                        segment_name,
2000                        &mut defaults_by_first_segment,
2001                    )?;
2002                    wip = sub.deserialize_into(wip)?;
2003                    wip = wip.end()?;
2004                    if is_option {
2005                        wip = wip.end()?; // End the Option field itself
2006                    }
2007                } else {
2008                    wip = sub.deserialize_into(wip)?;
2009                }
2010            }
2011        }
2012
2013        // Close any remaining open segments
2014        while let Some((segment_name, is_option)) = open_segments.pop() {
2015            wip =
2016                self.apply_defaults_for_segment(wip, segment_name, &mut defaults_by_first_segment)?;
2017            if is_option {
2018                wip = wip.end()?; // End the inner Some value
2019            }
2020            wip = wip.end()?; // End the field
2021        }
2022        for infos in defaults_by_first_segment.into_values() {
2023            for info in infos {
2024                wip = self.set_missing_field_default(wip, info, false)?;
2025            }
2026        }
2027
2028        Ok(wip)
2029    }
2030
2031    /// Deserialize an enum.
2032    ///
2033    /// Supports externally tagged representation: `{"VariantName": data}` or `"UnitVariant"`
2034    fn deserialize_enum(
2035        &mut self,
2036        mut wip: Partial<'input, BORROW>,
2037    ) -> Result<Partial<'input, BORROW>> {
2038        log::trace!("deserialize_enum: {}", wip.shape().type_identifier);
2039
2040        // Check if this is an untagged enum
2041        if wip.shape().is_untagged() {
2042            return self.deserialize_untagged_enum(wip);
2043        }
2044
2045        let token = self.peek()?;
2046
2047        match &token.token {
2048            // String = unit variant (externally tagged unit)
2049            Token::String(s) => {
2050                let variant_name = s.clone();
2051                self.next()?; // consume
2052
2053                wip = wip.select_variant_named(&variant_name)?;
2054                // Unit variants don't need further deserialization
2055                Ok(wip)
2056            }
2057            // Object = externally tagged variant with data
2058            Token::ObjectStart => {
2059                self.next()?; // consume brace
2060
2061                // Get the variant name (first key)
2062                let key_token = self.next()?;
2063                let key = match &key_token.token {
2064                    Token::String(s) => s.clone(),
2065                    Token::ObjectEnd => {
2066                        // Empty object - error
2067                        return Err(JsonError::new(
2068                            JsonErrorKind::InvalidValue {
2069                                message: "empty object cannot represent enum variant".into(),
2070                            },
2071                            key_token.span,
2072                        ));
2073                    }
2074                    _ => {
2075                        return Err(JsonError::new(
2076                            JsonErrorKind::UnexpectedToken {
2077                                got: format!("{:?}", key_token.token),
2078                                expected: "variant name",
2079                            },
2080                            key_token.span,
2081                        ));
2082                    }
2083                };
2084
2085                // Expect colon
2086                let colon = self.next()?;
2087                if !matches!(colon.token, Token::Colon) {
2088                    return Err(JsonError::new(
2089                        JsonErrorKind::UnexpectedToken {
2090                            got: format!("{:?}", colon.token),
2091                            expected: "':'",
2092                        },
2093                        colon.span,
2094                    ));
2095                }
2096
2097                // Select the variant
2098                wip = wip.select_variant_named(&key)?;
2099
2100                // Get the selected variant info to determine how to deserialize
2101                let variant = wip.selected_variant().ok_or_else(|| {
2102                    JsonError::without_span(JsonErrorKind::InvalidValue {
2103                        message: "failed to get selected variant".into(),
2104                    })
2105                })?;
2106
2107                // Deserialize based on variant kind
2108                match variant.data.kind {
2109                    StructKind::Unit => {
2110                        // Unit variant in object form like {"Unit": null}
2111                        // We should consume some token (null, empty object, etc.)
2112                        let tok = self.next()?;
2113                        if !matches!(tok.token, Token::Null) {
2114                            return Err(JsonError::new(
2115                                JsonErrorKind::UnexpectedToken {
2116                                    got: format!("{:?}", tok.token),
2117                                    expected: "null for unit variant",
2118                                },
2119                                tok.span,
2120                            ));
2121                        }
2122                    }
2123                    StructKind::TupleStruct | StructKind::Tuple => {
2124                        let num_fields = variant.data.fields.len();
2125                        if num_fields == 0 {
2126                            // Zero-field tuple variant, treat like unit
2127                            let tok = self.peek()?;
2128                            if matches!(tok.token, Token::Null) {
2129                                self.next()?;
2130                            }
2131                        } else if num_fields == 1 {
2132                            // Single-element tuple: value directly (e.g., {"X": 123})
2133                            let field = &variant.data.fields[0];
2134                            wip = wip.begin_nth_field(0)?;
2135                            // Check if field has custom deserialization
2136                            if field.proxy_convert_in_fn().is_some() {
2137                                wip = wip.begin_custom_deserialization()?;
2138                                wip = self.deserialize_into(wip)?;
2139                                wip = wip.end()?; // Calls deserialize_with function
2140                            } else {
2141                                wip = self.deserialize_into(wip)?;
2142                            }
2143                            wip = wip.end()?;
2144                        } else {
2145                            // Multi-element tuple: array (e.g., {"Y": ["hello", true]})
2146                            let tok = self.next()?;
2147                            if !matches!(tok.token, Token::ArrayStart) {
2148                                return Err(JsonError::new(
2149                                    JsonErrorKind::UnexpectedToken {
2150                                        got: format!("{:?}", tok.token),
2151                                        expected: "'[' for tuple variant",
2152                                    },
2153                                    tok.span,
2154                                ));
2155                            }
2156
2157                            for i in 0..num_fields {
2158                                let field = &variant.data.fields[i];
2159                                wip = wip.begin_nth_field(i)?;
2160                                // Check if field has custom deserialization
2161                                if field.proxy_convert_in_fn().is_some() {
2162                                    wip = wip.begin_custom_deserialization()?;
2163                                    wip = self.deserialize_into(wip)?;
2164                                    wip = wip.end()?; // Calls deserialize_with function
2165                                } else {
2166                                    wip = self.deserialize_into(wip)?;
2167                                }
2168                                wip = wip.end()?;
2169
2170                                // Check for comma or closing bracket
2171                                let next = self.peek()?;
2172                                if matches!(next.token, Token::Comma) {
2173                                    self.next()?;
2174                                }
2175                            }
2176
2177                            let close = self.next()?;
2178                            if !matches!(close.token, Token::ArrayEnd) {
2179                                return Err(JsonError::new(
2180                                    JsonErrorKind::UnexpectedToken {
2181                                        got: format!("{:?}", close.token),
2182                                        expected: "']'",
2183                                    },
2184                                    close.span,
2185                                ));
2186                            }
2187                        }
2188                    }
2189                    StructKind::Struct => {
2190                        // Struct variant: object with named fields
2191                        wip = self.deserialize_variant_struct_content(wip)?;
2192                    }
2193                }
2194
2195                // Expect closing brace for the outer object
2196                let close = self.next()?;
2197                if !matches!(close.token, Token::ObjectEnd) {
2198                    return Err(JsonError::new(
2199                        JsonErrorKind::UnexpectedToken {
2200                            got: format!("{:?}", close.token),
2201                            expected: "'}'",
2202                        },
2203                        close.span,
2204                    ));
2205                }
2206
2207                Ok(wip)
2208            }
2209            _ => {
2210                let span = token.span;
2211                Err(JsonError::new(
2212                    JsonErrorKind::UnexpectedToken {
2213                        got: format!("{:?}", token.token),
2214                        expected: "string or object for enum",
2215                    },
2216                    span,
2217                ))
2218            }
2219        }
2220    }
2221
2222    /// Deserialize an untagged enum using the Solver to determine which variant matches.
2223    ///
2224    /// For untagged enums, we use facet-solver to:
2225    /// 1. Record the start position of the object
2226    /// 2. Scan all JSON keys, feed them to the solver to narrow down candidates
2227    /// 3. Use finish() to determine which variant's required fields are satisfied
2228    /// 4. Rewind to start position and deserialize the whole object into the matched variant
2229    fn deserialize_untagged_enum(
2230        &mut self,
2231        mut wip: Partial<'input, BORROW>,
2232    ) -> Result<Partial<'input, BORROW>> {
2233        log::trace!("deserialize_untagged_enum: {}", wip.shape().type_identifier);
2234
2235        let shape = wip.shape();
2236
2237        // Build schema - this creates one resolution per variant for untagged enums
2238        let schema = Schema::build_auto(shape).map_err(|e| {
2239            JsonError::without_span(JsonErrorKind::Solver(format!(
2240                "failed to build schema: {e}"
2241            )))
2242        })?;
2243
2244        // Create the solver
2245        let mut solver = Solver::new(&schema);
2246
2247        // Expect opening brace (struct variants) or handle other cases
2248        let token = self.peek()?;
2249        match &token.token {
2250            Token::ObjectStart => {
2251                // Record start position for rewinding after we determine the variant
2252                let start_offset = token.span.offset;
2253
2254                self.next()?; // consume the brace
2255
2256                // ========== PASS 1: Scan all keys, feed to solver ==========
2257                loop {
2258                    let token = self.peek()?;
2259                    match &token.token {
2260                        Token::ObjectEnd => {
2261                            self.next()?;
2262                            break;
2263                        }
2264                        Token::String(_) => {
2265                            let key_token = self.next()?;
2266                            let key = match &key_token.token {
2267                                Token::String(s) => s.clone(),
2268                                _ => unreachable!(),
2269                            };
2270
2271                            let colon = self.next()?;
2272                            if !matches!(colon.token, Token::Colon) {
2273                                return Err(JsonError::new(
2274                                    JsonErrorKind::UnexpectedToken {
2275                                        got: format!("{:?}", colon.token),
2276                                        expected: "':'",
2277                                    },
2278                                    colon.span,
2279                                ));
2280                            }
2281
2282                            // Feed key to solver
2283                            let _decision = solver.see_key(key);
2284
2285                            // Skip the value
2286                            self.skip_value()?;
2287
2288                            // Check for comma
2289                            let next = self.peek()?;
2290                            if matches!(next.token, Token::Comma) {
2291                                self.next()?;
2292                            }
2293                        }
2294                        _ => {
2295                            let span = token.span;
2296                            return Err(JsonError::new(
2297                                JsonErrorKind::UnexpectedToken {
2298                                    got: format!("{:?}", token.token),
2299                                    expected: "field name or '}'",
2300                                },
2301                                span,
2302                            ));
2303                        }
2304                    }
2305                }
2306
2307                // ========== Get the resolved variant ==========
2308                let config_handle = solver
2309                    .finish()
2310                    .map_err(|e| JsonError::without_span(JsonErrorKind::Solver(format!("{e}"))))?;
2311                let config = config_handle.resolution();
2312
2313                // Extract the variant name from the resolution
2314                let variant_name = config
2315                    .variant_selections()
2316                    .first()
2317                    .map(|vs| vs.variant_name)
2318                    .ok_or_else(|| {
2319                        JsonError::without_span(JsonErrorKind::InvalidValue {
2320                            message: "solver returned resolution with no variant selection".into(),
2321                        })
2322                    })?;
2323
2324                // Select the variant
2325                wip = wip.select_variant_named(variant_name)?;
2326
2327                // ========== PASS 2: Rewind and deserialize ==========
2328                // Create a new deserializer at the start of the object
2329                let rewound_adapter = self.adapter.at_offset(start_offset).ok_or_else(|| {
2330                    JsonError::without_span(JsonErrorKind::InvalidValue {
2331                        message: "untagged enums not supported in streaming mode".into(),
2332                    })
2333                })?;
2334                let mut rewound_deser = Self::from_adapter(rewound_adapter);
2335
2336                // Deserialize the object into the selected variant
2337                wip = rewound_deser.deserialize_variant_struct_content(wip)?;
2338
2339                Ok(wip)
2340            }
2341            Token::ArrayStart => {
2342                // Tuple variants - match by arity
2343                self.deserialize_untagged_tuple_variant(wip, shape)
2344            }
2345            Token::Null => {
2346                // Unit variants - select the first unit variant
2347                self.deserialize_untagged_unit_variant(wip, shape)
2348            }
2349            Token::String(_)
2350            | Token::I64(_)
2351            | Token::U64(_)
2352            | Token::I128(_)
2353            | Token::U128(_)
2354            | Token::F64(_)
2355            | Token::True
2356            | Token::False => {
2357                // Scalar variants - select based on value type
2358                self.deserialize_untagged_scalar_variant(wip, shape)
2359            }
2360            _ => Err(JsonError::new(
2361                JsonErrorKind::InvalidValue {
2362                    message: format!("unexpected token {:?} for untagged enum", token.token),
2363                },
2364                token.span,
2365            )),
2366        }
2367    }
2368
2369    /// Deserialize an untagged enum from a null value.
2370    /// Selects the first unit variant.
2371    fn deserialize_untagged_unit_variant(
2372        &mut self,
2373        mut wip: Partial<'input, BORROW>,
2374        shape: &'static Shape,
2375    ) -> Result<Partial<'input, BORROW>> {
2376        let variants_by_format = VariantsByFormat::from_shape(shape).ok_or_else(|| {
2377            JsonError::without_span(JsonErrorKind::InvalidValue {
2378                message: "expected enum shape for untagged deserialization".into(),
2379            })
2380        })?;
2381
2382        if variants_by_format.unit_variants.is_empty() {
2383            return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
2384                message: format!(
2385                    "no unit variants in untagged enum {} for null value",
2386                    shape.type_identifier
2387                ),
2388            }));
2389        }
2390
2391        // Consume the null token
2392        self.next()?;
2393
2394        // Select the first unit variant (like serde does)
2395        let variant = variants_by_format.unit_variants[0];
2396        wip = wip.select_variant_named(variant.name)?;
2397
2398        Ok(wip)
2399    }
2400
2401    /// Deserialize an untagged enum from a scalar value (string, number, bool).
2402    /// Selects the variant based on the value type.
2403    fn deserialize_untagged_scalar_variant(
2404        &mut self,
2405        mut wip: Partial<'input, BORROW>,
2406        shape: &'static Shape,
2407    ) -> Result<Partial<'input, BORROW>> {
2408        let variants_by_format = VariantsByFormat::from_shape(shape).ok_or_else(|| {
2409            JsonError::without_span(JsonErrorKind::InvalidValue {
2410                message: "expected enum shape for untagged deserialization".into(),
2411            })
2412        })?;
2413
2414        // Check if we have a string token that matches a unit variant name
2415        let token = self.peek()?.clone();
2416        if let Token::String(ref s) = token.token {
2417            // Try to find a unit variant with this name
2418            for variant in &variants_by_format.unit_variants {
2419                if variant.name == s.as_ref() {
2420                    // This is a unit variant - consume the string and select it
2421                    self.next()?;
2422                    wip = wip.select_variant_named(variant.name)?;
2423                    return Ok(wip);
2424                }
2425            }
2426        }
2427
2428        // Not a unit variant - fall back to newtype scalar variant handling
2429        if variants_by_format.scalar_variants.is_empty() {
2430            return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
2431                message: format!(
2432                    "no scalar-accepting variants in untagged enum {}",
2433                    shape.type_identifier
2434                ),
2435            }));
2436        }
2437
2438        // Select the variant based on the token type
2439        let variant_name = self.select_scalar_variant(&variants_by_format, &token)?;
2440
2441        wip = wip.select_variant_named(variant_name)?;
2442        wip = wip.begin_nth_field(0)?;
2443        wip = self.deserialize_into(wip)?;
2444        wip = wip.end()?;
2445
2446        Ok(wip)
2447    }
2448
2449    /// Select which scalar variant to use based on the JSON token.
2450    fn select_scalar_variant(
2451        &self,
2452        variants: &VariantsByFormat,
2453        token: &SpannedAdapterToken,
2454    ) -> Result<&'static str> {
2455        // Sort by specificity (most specific first)
2456        let mut candidates: Vec<_> = variants.scalar_variants.clone();
2457        candidates.sort_by_key(|(_, inner_shape)| specificity_score(inner_shape));
2458
2459        match &token.token {
2460            Token::True | Token::False => {
2461                // Find a bool variant
2462                for (variant, inner_shape) in &candidates {
2463                    if inner_shape.scalar_type() == Some(ScalarType::Bool) {
2464                        return Ok(variant.name);
2465                    }
2466                }
2467            }
2468            Token::I64(n) => {
2469                // Find the smallest integer type that fits
2470                let n = *n;
2471                for (variant, inner_shape) in &candidates {
2472                    let fits = match inner_shape.scalar_type() {
2473                        Some(ScalarType::U8) => n >= 0 && n <= u8::MAX as i64,
2474                        Some(ScalarType::U16) => n >= 0 && n <= u16::MAX as i64,
2475                        Some(ScalarType::U32) => n >= 0 && n <= u32::MAX as i64,
2476                        Some(ScalarType::U64) => n >= 0,
2477                        Some(ScalarType::I8) => n >= i8::MIN as i64 && n <= i8::MAX as i64,
2478                        Some(ScalarType::I16) => n >= i16::MIN as i64 && n <= i16::MAX as i64,
2479                        Some(ScalarType::I32) => n >= i32::MIN as i64 && n <= i32::MAX as i64,
2480                        Some(ScalarType::I64) => true,
2481                        Some(ScalarType::F32) | Some(ScalarType::F64) => true,
2482                        _ => false,
2483                    };
2484                    if fits {
2485                        return Ok(variant.name);
2486                    }
2487                }
2488            }
2489            Token::U64(n) => {
2490                let n = *n;
2491                for (variant, inner_shape) in &candidates {
2492                    let fits = match inner_shape.scalar_type() {
2493                        Some(ScalarType::U8) => n <= u8::MAX as u64,
2494                        Some(ScalarType::U16) => n <= u16::MAX as u64,
2495                        Some(ScalarType::U32) => n <= u32::MAX as u64,
2496                        Some(ScalarType::U64) => true,
2497                        Some(ScalarType::I8) => n <= i8::MAX as u64,
2498                        Some(ScalarType::I16) => n <= i16::MAX as u64,
2499                        Some(ScalarType::I32) => n <= i32::MAX as u64,
2500                        Some(ScalarType::I64) => n <= i64::MAX as u64,
2501                        Some(ScalarType::F32) | Some(ScalarType::F64) => true,
2502                        _ => false,
2503                    };
2504                    if fits {
2505                        return Ok(variant.name);
2506                    }
2507                }
2508            }
2509            Token::I128(n) => {
2510                let n = *n;
2511                for (variant, inner_shape) in &candidates {
2512                    let fits = match inner_shape.scalar_type() {
2513                        Some(ScalarType::I128) => true,
2514                        Some(ScalarType::U128) => n >= 0,
2515                        _ => false,
2516                    };
2517                    if fits {
2518                        return Ok(variant.name);
2519                    }
2520                }
2521            }
2522            Token::U128(n) => {
2523                let n = *n;
2524                for (variant, inner_shape) in &candidates {
2525                    let fits = match inner_shape.scalar_type() {
2526                        Some(ScalarType::U128) => true,
2527                        Some(ScalarType::I128) => n <= i128::MAX as u128,
2528                        _ => false,
2529                    };
2530                    if fits {
2531                        return Ok(variant.name);
2532                    }
2533                }
2534            }
2535            Token::F64(_) => {
2536                // Find a float variant
2537                for (variant, inner_shape) in &candidates {
2538                    if matches!(
2539                        inner_shape.scalar_type(),
2540                        Some(ScalarType::F32) | Some(ScalarType::F64)
2541                    ) {
2542                        return Ok(variant.name);
2543                    }
2544                }
2545            }
2546            Token::String(_) => {
2547                // Find a string-like variant
2548                for (variant, inner_shape) in &candidates {
2549                    if matches!(
2550                        inner_shape.scalar_type(),
2551                        Some(ScalarType::String) | Some(ScalarType::Str) | Some(ScalarType::CowStr)
2552                    ) || inner_shape.scalar_type().is_none()
2553                    {
2554                        return Ok(variant.name);
2555                    }
2556                }
2557            }
2558            _ => {}
2559        }
2560
2561        // Fall back to the first scalar variant if no specific match
2562        if let Some((variant, _)) = candidates.first() {
2563            return Ok(variant.name);
2564        }
2565
2566        Err(JsonError::new(
2567            JsonErrorKind::InvalidValue {
2568                message: format!("no matching scalar variant for token {:?}", token.token),
2569            },
2570            token.span,
2571        ))
2572    }
2573
2574    /// Deserialize an untagged enum from an array (tuple variant).
2575    fn deserialize_untagged_tuple_variant(
2576        &mut self,
2577        mut wip: Partial<'input, BORROW>,
2578        shape: &'static Shape,
2579    ) -> Result<Partial<'input, BORROW>> {
2580        let variants_by_format = VariantsByFormat::from_shape(shape).ok_or_else(|| {
2581            JsonError::without_span(JsonErrorKind::InvalidValue {
2582                message: "expected enum shape for untagged deserialization".into(),
2583            })
2584        })?;
2585
2586        if variants_by_format.tuple_variants.is_empty() {
2587            return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
2588                message: format!(
2589                    "no tuple variants in untagged enum {} for array value",
2590                    shape.type_identifier
2591                ),
2592            }));
2593        }
2594
2595        // Record start position for rewinding
2596        let start_token = self.peek()?;
2597        let start_offset = start_token.span.offset;
2598
2599        // Count the array elements
2600        self.next()?; // consume ArrayStart
2601        let mut arity = 0;
2602        loop {
2603            let token = self.peek()?;
2604            match &token.token {
2605                Token::ArrayEnd => {
2606                    self.next()?;
2607                    break;
2608                }
2609                _ => {
2610                    arity += 1;
2611                    self.skip_value()?;
2612                    // Skip comma if present
2613                    let next = self.peek()?;
2614                    if matches!(next.token, Token::Comma) {
2615                        self.next()?;
2616                    }
2617                }
2618            }
2619        }
2620
2621        // Find variants with matching arity
2622        let matching_variants = variants_by_format.tuple_variants_with_arity(arity);
2623        if matching_variants.is_empty() {
2624            return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
2625                message: format!(
2626                    "no tuple variant with arity {} in untagged enum {}",
2627                    arity, shape.type_identifier
2628                ),
2629            }));
2630        }
2631
2632        // Select the first matching variant
2633        let variant = matching_variants[0];
2634        wip = wip.select_variant_named(variant.name)?;
2635        let is_newtype = variant.data.fields.len() == 1;
2636
2637        // Rewind and deserialize
2638        let rewound_adapter = self.adapter.at_offset(start_offset).ok_or_else(|| {
2639            JsonError::without_span(JsonErrorKind::InvalidValue {
2640                message: "untagged tuple variants not supported in streaming mode".into(),
2641            })
2642        })?;
2643        let mut rewound_deser = Self::from_adapter(rewound_adapter);
2644
2645        if is_newtype {
2646            // Deserialize the entire array into the inner tuple value
2647            wip = wip.begin_nth_field(0)?;
2648            wip = rewound_deser.deserialize_into(wip)?;
2649            wip = wip.end()?;
2650        } else {
2651            // Consume ArrayStart
2652            rewound_deser.next()?;
2653
2654            // Deserialize each field
2655            for i in 0..arity {
2656                wip = wip.begin_nth_field(i)?;
2657                wip = rewound_deser.deserialize_into(wip)?;
2658                wip = wip.end()?;
2659
2660                // Skip comma if present
2661                let next = rewound_deser.peek()?;
2662                if matches!(next.token, Token::Comma) {
2663                    rewound_deser.next()?;
2664                }
2665            }
2666
2667            debug_assert_eq!(
2668                variant.data.fields.len(),
2669                arity,
2670                "tuple variant arity should match array length"
2671            );
2672
2673            // Consume ArrayEnd
2674            rewound_deser.next()?;
2675        }
2676
2677        Ok(wip)
2678    }
2679
2680    /// Deserialize the content of an enum variant in a flattened context.
2681    /// Handles both struct variants and tuple variants.
2682    fn deserialize_variant_struct_content(
2683        &mut self,
2684        mut wip: Partial<'input, BORROW>,
2685    ) -> Result<Partial<'input, BORROW>> {
2686        // Check what kind of variant we have
2687        let variant = wip.selected_variant().ok_or_else(|| {
2688            JsonError::without_span(JsonErrorKind::InvalidValue {
2689                message: "no variant selected".into(),
2690            })
2691        })?;
2692
2693        let is_struct_variant = variant
2694            .data
2695            .fields
2696            .first()
2697            .map(|f| !f.name.starts_with(|c: char| c.is_ascii_digit()))
2698            .unwrap_or(true);
2699
2700        if is_struct_variant {
2701            // Struct variant: {"field1": ..., "field2": ...}
2702            self.deserialize_variant_struct_fields(wip, variant.data.fields)
2703        } else if variant.data.fields.len() == 1 {
2704            // Single-element tuple variant: just the value (not wrapped)
2705            let field = &variant.data.fields[0];
2706            wip = wip.begin_nth_field(0)?;
2707            // Check if field has custom deserialization
2708            if field.proxy_convert_in_fn().is_some() {
2709                wip = wip.begin_custom_deserialization()?;
2710                wip = self.deserialize_into(wip)?;
2711                wip = wip.end()?;
2712            } else {
2713                wip = self.deserialize_into(wip)?;
2714            }
2715            wip = wip.end()?;
2716            Ok(wip)
2717        } else {
2718            // Multi-element tuple variant: [val1, val2, ...]
2719            self.deserialize_variant_tuple_fields(wip)
2720        }
2721    }
2722
2723    /// Deserialize struct fields of a variant.
2724    fn deserialize_variant_struct_fields(
2725        &mut self,
2726        mut wip: Partial<'input, BORROW>,
2727        fields: &[facet_core::Field],
2728    ) -> Result<Partial<'input, BORROW>> {
2729        let token = self.next()?;
2730        if !matches!(token.token, Token::ObjectStart) {
2731            return Err(JsonError::new(
2732                JsonErrorKind::UnexpectedToken {
2733                    got: format!("{:?}", token.token),
2734                    expected: "'{' for struct variant",
2735                },
2736                token.span,
2737            ));
2738        }
2739
2740        loop {
2741            let token = self.peek()?;
2742            if matches!(token.token, Token::ObjectEnd) {
2743                self.next()?;
2744                break;
2745            }
2746
2747            let key_token = self.next()?;
2748            let field_name = match &key_token.token {
2749                Token::String(s) => s.clone(),
2750                _ => {
2751                    return Err(JsonError::new(
2752                        JsonErrorKind::UnexpectedToken {
2753                            got: format!("{:?}", key_token.token),
2754                            expected: "field name",
2755                        },
2756                        key_token.span,
2757                    ));
2758                }
2759            };
2760
2761            let colon = self.next()?;
2762            if !matches!(colon.token, Token::Colon) {
2763                return Err(JsonError::new(
2764                    JsonErrorKind::UnexpectedToken {
2765                        got: format!("{:?}", colon.token),
2766                        expected: "':'",
2767                    },
2768                    colon.span,
2769                ));
2770            }
2771
2772            // Find the field in the variant's fields to check for custom deserialization
2773            let field_info = fields.iter().find(|f| f.name == field_name.as_ref());
2774
2775            if let Some(field) = field_info {
2776                wip = wip.begin_field(field.name)?;
2777                // Check if field has custom deserialization
2778                if field.proxy_convert_in_fn().is_some() {
2779                    wip = wip.begin_custom_deserialization()?;
2780                    wip = self.deserialize_into(wip)?;
2781                    wip = wip.end()?; // Calls deserialize_with function
2782                } else {
2783                    wip = self.deserialize_into(wip)?;
2784                }
2785                wip = wip.end()?;
2786            } else {
2787                // Unknown field, skip its value
2788                self.skip_value()?;
2789            }
2790
2791            let next = self.peek()?;
2792            if matches!(next.token, Token::Comma) {
2793                self.next()?;
2794            }
2795        }
2796
2797        Ok(wip)
2798    }
2799
2800    /// Deserialize tuple fields of a variant.
2801    fn deserialize_variant_tuple_fields(
2802        &mut self,
2803        mut wip: Partial<'input, BORROW>,
2804    ) -> Result<Partial<'input, BORROW>> {
2805        let token = self.next()?;
2806        if !matches!(token.token, Token::ArrayStart) {
2807            return Err(JsonError::new(
2808                JsonErrorKind::UnexpectedToken {
2809                    got: format!("{:?}", token.token),
2810                    expected: "'[' for tuple variant",
2811                },
2812                token.span,
2813            ));
2814        }
2815
2816        let mut idx = 0;
2817        loop {
2818            let token = self.peek()?;
2819            if matches!(token.token, Token::ArrayEnd) {
2820                self.next()?;
2821                break;
2822            }
2823
2824            // Deserialize into field "0", "1", "2", etc.
2825            let field_name = alloc::format!("{idx}");
2826            wip = wip.begin_field(&field_name)?;
2827            wip = self.deserialize_into(wip)?;
2828            wip = wip.end()?;
2829
2830            idx += 1;
2831            let next = self.peek()?;
2832            if matches!(next.token, Token::Comma) {
2833                self.next()?;
2834            }
2835        }
2836
2837        Ok(wip)
2838    }
2839
2840    /// Deserialize a list/Vec.
2841    fn deserialize_list(
2842        &mut self,
2843        mut wip: Partial<'input, BORROW>,
2844    ) -> Result<Partial<'input, BORROW>> {
2845        log::trace!("deserialize_list");
2846
2847        let token = self.next()?;
2848        if !matches!(token.token, Token::ArrayStart) {
2849            return Err(JsonError::new(
2850                JsonErrorKind::UnexpectedToken {
2851                    got: format!("{:?}", token.token),
2852                    expected: "'['",
2853                },
2854                token.span,
2855            ));
2856        }
2857
2858        wip = wip.begin_list()?;
2859
2860        loop {
2861            let token = self.peek()?;
2862            if matches!(token.token, Token::ArrayEnd) {
2863                self.next()?;
2864                break;
2865            }
2866
2867            wip = wip.begin_list_item()?;
2868            wip = self.deserialize_into(wip)?;
2869            wip = wip.end()?; // End the list item frame
2870
2871            let next = self.peek()?;
2872            if matches!(next.token, Token::Comma) {
2873                self.next()?;
2874            }
2875        }
2876
2877        // Note: begin_list() does not push a frame, so we don't call end() here
2878        Ok(wip)
2879    }
2880
2881    /// Deserialize a map.
2882    fn deserialize_map(
2883        &mut self,
2884        mut wip: Partial<'input, BORROW>,
2885    ) -> Result<Partial<'input, BORROW>> {
2886        log::trace!("deserialize_map");
2887
2888        let token = self.next()?;
2889        if !matches!(token.token, Token::ObjectStart) {
2890            return Err(JsonError::new(
2891                JsonErrorKind::UnexpectedToken {
2892                    got: format!("{:?}", token.token),
2893                    expected: "'{'",
2894                },
2895                token.span,
2896            ));
2897        }
2898
2899        wip = wip.begin_map()?;
2900
2901        loop {
2902            let token = self.peek()?;
2903            if matches!(token.token, Token::ObjectEnd) {
2904                self.next()?;
2905                break;
2906            }
2907
2908            // Key
2909            let key_token = self.next()?;
2910            let key = match key_token.token {
2911                Token::String(s) => s,
2912                _ => {
2913                    return Err(JsonError::new(
2914                        JsonErrorKind::UnexpectedToken {
2915                            got: format!("{:?}", key_token.token),
2916                            expected: "string key",
2917                        },
2918                        key_token.span,
2919                    ));
2920                }
2921            };
2922
2923            // Colon
2924            let colon = self.next()?;
2925            if !matches!(colon.token, Token::Colon) {
2926                return Err(JsonError::new(
2927                    JsonErrorKind::UnexpectedToken {
2928                        got: format!("{:?}", colon.token),
2929                        expected: "':'",
2930                    },
2931                    colon.span,
2932                ));
2933            }
2934
2935            // Set key - begin_key pushes a frame for the key type
2936            wip = wip.begin_key()?;
2937            wip = self.deserialize_map_key(wip, key, key_token.span)?;
2938            wip = wip.end()?;
2939
2940            // Value - begin_value pushes a frame
2941            wip = wip.begin_value()?;
2942            wip = self.deserialize_into(wip)?;
2943            wip = wip.end()?;
2944
2945            // Comma or end
2946            let next = self.peek()?;
2947            if matches!(next.token, Token::Comma) {
2948                self.next()?;
2949            }
2950        }
2951
2952        // Note: begin_map() does not push a frame, so we don't call end() here
2953        Ok(wip)
2954    }
2955
2956    /// Deserialize an Option.
2957    fn deserialize_option(
2958        &mut self,
2959        mut wip: Partial<'input, BORROW>,
2960    ) -> Result<Partial<'input, BORROW>> {
2961        log::trace!("deserialize_option");
2962
2963        let token = self.peek()?;
2964        if matches!(token.token, Token::Null) {
2965            self.next()?;
2966            wip = wip.set_default()?; // None
2967        } else {
2968            log::trace!("deserialize_option: calling begin_some");
2969            wip = wip.begin_some()?;
2970            log::trace!("deserialize_option: begin_some succeeded, calling deserialize_into");
2971            wip = self.deserialize_into(wip)?;
2972            log::trace!("deserialize_option: deserialize_into succeeded, calling end");
2973            wip = wip.end()?;
2974            log::trace!("deserialize_option: end succeeded");
2975        }
2976        Ok(wip)
2977    }
2978
2979    /// Deserialize a smart pointer (Box, Arc, Rc) or reference (&str).
2980    fn deserialize_pointer(
2981        &mut self,
2982        mut wip: Partial<'input, BORROW>,
2983    ) -> Result<Partial<'input, BORROW>> {
2984        log::trace!("deserialize_pointer");
2985
2986        // Check what kind of pointer this is BEFORE calling begin_smart_ptr
2987        let (is_slice_pointer, is_reference, is_str_ref, is_cow_str) =
2988            if let Def::Pointer(ptr_def) = wip.shape().def {
2989                let is_slice = if let Some(pointee) = ptr_def.pointee() {
2990                    matches!(pointee.ty, Type::Sequence(SequenceType::Slice(_)))
2991                } else {
2992                    false
2993                };
2994                let is_ref = matches!(
2995                    ptr_def.known,
2996                    Some(KnownPointer::SharedReference | KnownPointer::ExclusiveReference)
2997                );
2998                // Special case: &str can be deserialized by borrowing from input
2999                let is_str_ref = matches!(ptr_def.known, Some(KnownPointer::SharedReference))
3000                    && ptr_def
3001                        .pointee()
3002                        .is_some_and(|p| p.type_identifier == "str");
3003                // Special case: Cow<str> can borrow or own depending on whether escaping was needed
3004                let is_cow_str = matches!(ptr_def.known, Some(KnownPointer::Cow))
3005                    && ptr_def
3006                        .pointee()
3007                        .is_some_and(|p| p.type_identifier == "str");
3008                (is_slice, is_ref, is_str_ref, is_cow_str)
3009            } else {
3010                (false, false, false, false)
3011            };
3012
3013        // Special case: Cow<str> can be deserialized directly from string tokens
3014        // preserving borrowed/owned status based on whether escaping was needed
3015        if is_cow_str {
3016            let token = self.next()?;
3017            match token.token {
3018                Token::String(s) => {
3019                    // Zero-copy Cow<str>: preserve borrowed/owned status
3020                    wip = wip.set(s)?;
3021                    return Ok(wip);
3022                }
3023                _ => {
3024                    return Err(JsonError::new(
3025                        JsonErrorKind::UnexpectedToken {
3026                            got: format!("{:?}", token.token),
3027                            expected: "string",
3028                        },
3029                        token.span,
3030                    ));
3031                }
3032            }
3033        }
3034
3035        // Special case: &str can borrow directly from input if no escaping needed
3036        if is_str_ref {
3037            // In owned mode, we cannot borrow from input at all
3038            if !BORROW {
3039                return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
3040                    message: "cannot deserialize into &str when borrowing is disabled - use String or Cow<str> instead".into(),
3041                }));
3042            }
3043            let token = self.next()?;
3044            match token.token {
3045                Token::String(Cow::Borrowed(s)) => {
3046                    // Zero-copy: borrow directly from input
3047                    wip = wip.set(s)?;
3048                    return Ok(wip);
3049                }
3050                Token::String(Cow::Owned(_)) => {
3051                    return Err(JsonError::new(
3052                        JsonErrorKind::InvalidValue {
3053                            message: "cannot borrow &str from JSON string containing escape sequences - use String instead".into(),
3054                        },
3055                        token.span,
3056                    ));
3057                }
3058                _ => {
3059                    return Err(JsonError::new(
3060                        JsonErrorKind::UnexpectedToken {
3061                            got: format!("{:?}", token.token),
3062                            expected: "string",
3063                        },
3064                        token.span,
3065                    ));
3066                }
3067            }
3068        }
3069
3070        // Other references (&T, &mut T) cannot be deserialized - they require borrowing from
3071        // existing data, which isn't possible when deserializing from owned JSON
3072        if is_reference {
3073            return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
3074                message: format!(
3075                    "cannot deserialize into reference type '{wip}' - references require borrowing from existing data",
3076                    wip = wip.shape().type_identifier
3077                ),
3078            }));
3079        }
3080
3081        // For smart pointers, push_smart_ptr will handle:
3082        // - Sized pointees: allocates space for the inner type
3083        // - str pointee: allocates a String that gets converted to Box<str>/Arc<str>/Rc<str>
3084        // - [T] pointee: sets up a slice builder for Arc<[T]>/Box<[T]>/Rc<[T]>
3085        wip = wip.begin_smart_ptr()?;
3086
3087        if is_slice_pointer {
3088            // This is a slice pointer like Arc<[T]> - deserialize as array
3089            let token = self.next()?;
3090            if !matches!(token.token, Token::ArrayStart) {
3091                return Err(JsonError::new(
3092                    JsonErrorKind::UnexpectedToken {
3093                        got: format!("{:?}", token.token),
3094                        expected: "'['",
3095                    },
3096                    token.span,
3097                ));
3098            }
3099
3100            // Peek to check for empty array
3101            let first = self.peek()?;
3102            if matches!(first.token, Token::ArrayEnd) {
3103                self.next()?; // consume the RBracket
3104                wip = wip.end()?;
3105                return Ok(wip);
3106            }
3107
3108            // Deserialize elements
3109            loop {
3110                wip = wip.begin_list_item()?;
3111                wip = self.deserialize_into(wip)?;
3112                wip = wip.end()?;
3113
3114                let next = self.next()?;
3115                match next.token {
3116                    Token::Comma => continue,
3117                    Token::ArrayEnd => break,
3118                    _ => {
3119                        return Err(JsonError::new(
3120                            JsonErrorKind::UnexpectedToken {
3121                                got: format!("{:?}", next.token),
3122                                expected: "',' or ']'",
3123                            },
3124                            next.span,
3125                        ));
3126                    }
3127                }
3128            }
3129
3130            wip = wip.end()?;
3131            return Ok(wip);
3132        }
3133
3134        // For non-slice pointers, deserialize the inner type directly
3135        wip = self.deserialize_into(wip)?;
3136        wip = wip.end()?;
3137        Ok(wip)
3138    }
3139
3140    /// Deserialize a fixed-size array.
3141    fn deserialize_array(
3142        &mut self,
3143        mut wip: Partial<'input, BORROW>,
3144    ) -> Result<Partial<'input, BORROW>> {
3145        log::trace!("deserialize_array");
3146
3147        let token = self.next()?;
3148        if !matches!(token.token, Token::ArrayStart) {
3149            return Err(JsonError::new(
3150                JsonErrorKind::UnexpectedToken {
3151                    got: format!("{:?}", token.token),
3152                    expected: "'['",
3153                },
3154                token.span,
3155            ));
3156        }
3157
3158        // Get array length from the Def
3159        let array_len = match &wip.shape().def {
3160            Def::Array(arr) => arr.n,
3161            _ => {
3162                return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
3163                    message: "expected array type".into(),
3164                }));
3165            }
3166        };
3167
3168        // Deserialize each element by index
3169        for i in 0..array_len {
3170            if i > 0 {
3171                let comma = self.next()?;
3172                if !matches!(comma.token, Token::Comma) {
3173                    return Err(JsonError::new(
3174                        JsonErrorKind::UnexpectedToken {
3175                            got: format!("{:?}", comma.token),
3176                            expected: "','",
3177                        },
3178                        comma.span,
3179                    ));
3180                }
3181            }
3182
3183            wip = wip.begin_nth_field(i)?;
3184            wip = self.deserialize_into(wip)?;
3185            wip = wip.end()?;
3186        }
3187
3188        let close = self.next()?;
3189        if !matches!(close.token, Token::ArrayEnd) {
3190            // If we got a comma, that means there are more elements than the fixed array can hold
3191            if matches!(close.token, Token::Comma) {
3192                return Err(JsonError::new(
3193                    JsonErrorKind::InvalidValue {
3194                        message: format!(
3195                            "Too many elements in array, maximum {array_len} elements"
3196                        ),
3197                    },
3198                    close.span,
3199                ));
3200            }
3201            return Err(JsonError::new(
3202                JsonErrorKind::UnexpectedToken {
3203                    got: format!("{:?}", close.token),
3204                    expected: "']'",
3205                },
3206                close.span,
3207            ));
3208        }
3209
3210        Ok(wip)
3211    }
3212
3213    /// Deserialize a set.
3214    fn deserialize_set(
3215        &mut self,
3216        mut wip: Partial<'input, BORROW>,
3217    ) -> Result<Partial<'input, BORROW>> {
3218        log::trace!("deserialize_set");
3219
3220        let token = self.next()?;
3221        if !matches!(token.token, Token::ArrayStart) {
3222            return Err(JsonError::new(
3223                JsonErrorKind::UnexpectedToken {
3224                    got: format!("{:?}", token.token),
3225                    expected: "'['",
3226                },
3227                token.span,
3228            ));
3229        }
3230
3231        wip = wip.begin_set()?;
3232
3233        loop {
3234            let token = self.peek()?;
3235            if matches!(token.token, Token::ArrayEnd) {
3236                self.next()?;
3237                break;
3238            }
3239
3240            wip = wip.begin_set_item()?;
3241            wip = self.deserialize_into(wip)?;
3242            wip = wip.end()?; // End the set item frame
3243
3244            let next = self.peek()?;
3245            if matches!(next.token, Token::Comma) {
3246                self.next()?;
3247            }
3248        }
3249
3250        // Note: begin_set() does not push a frame, so we don't call end() here
3251        Ok(wip)
3252    }
3253
3254    /// Deserialize a tuple.
3255    fn deserialize_tuple(
3256        &mut self,
3257        mut wip: Partial<'input, BORROW>,
3258    ) -> Result<Partial<'input, BORROW>> {
3259        log::trace!("deserialize_tuple");
3260
3261        let token = self.next()?;
3262        if !matches!(token.token, Token::ArrayStart) {
3263            return Err(JsonError::new(
3264                JsonErrorKind::UnexpectedToken {
3265                    got: format!("{:?}", token.token),
3266                    expected: "'['",
3267                },
3268                token.span,
3269            ));
3270        }
3271
3272        // Get tuple info from the struct definition
3273        let tuple_len = match &wip.shape().ty {
3274            Type::User(UserType::Struct(struct_def)) => struct_def.fields.len(),
3275            _ => {
3276                return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
3277                    message: "expected tuple type".into(),
3278                }));
3279            }
3280        };
3281
3282        for i in 0..tuple_len {
3283            if i > 0 {
3284                let comma = self.next()?;
3285                if !matches!(comma.token, Token::Comma) {
3286                    return Err(JsonError::new(
3287                        JsonErrorKind::UnexpectedToken {
3288                            got: format!("{:?}", comma.token),
3289                            expected: "','",
3290                        },
3291                        comma.span,
3292                    ));
3293                }
3294            }
3295
3296            wip = wip.begin_nth_field(i)?;
3297            wip = self.deserialize_into(wip)?;
3298            wip = wip.end()?;
3299        }
3300
3301        let close = self.next()?;
3302        if !matches!(close.token, Token::ArrayEnd) {
3303            return Err(JsonError::new(
3304                JsonErrorKind::UnexpectedToken {
3305                    got: format!("{:?}", close.token),
3306                    expected: "']'",
3307                },
3308                close.span,
3309            ));
3310        }
3311
3312        Ok(wip)
3313    }
3314
3315    fn set_missing_field_default(
3316        &mut self,
3317        mut wip: Partial<'input, BORROW>,
3318        field_info: &FieldInfo,
3319        skip_first_segment: bool,
3320    ) -> Result<Partial<'input, BORROW>> {
3321        log::trace!(
3322            "Initializing missing optional field '{}' via solver path {:?}",
3323            field_info.serialized_name,
3324            field_info.path
3325        );
3326        let segments = field_info.path.segments();
3327        if segments.is_empty() {
3328            return Self::apply_default_for_field(wip, field_info.field);
3329        }
3330
3331        #[allow(unused_mut, unused_variables)]
3332        let mut guards: Vec<PathGuard> = Vec::new();
3333
3334        for (idx, segment) in segments
3335            .iter()
3336            .take(segments.len().saturating_sub(1))
3337            .enumerate()
3338        {
3339            if skip_first_segment && idx == 0 {
3340                continue;
3341            }
3342            match segment {
3343                PathSegment::Field(name) => {
3344                    wip = wip.begin_field(name)?;
3345                    let is_option = matches!(wip.shape().def, Def::Option(_));
3346                    if is_option {
3347                        wip = wip.begin_some()?;
3348                    }
3349                    guards.push(PathGuard::Field {
3350                        had_option: is_option,
3351                    });
3352                }
3353                PathSegment::Variant(_, variant_name) => {
3354                    wip = wip.select_variant_named(variant_name)?;
3355                    guards.push(PathGuard::Variant);
3356                }
3357            }
3358        }
3359
3360        wip = Self::apply_default_for_field(wip, field_info.field)?;
3361
3362        while let Some(guard) = guards.pop() {
3363            match guard {
3364                PathGuard::Field { had_option } => {
3365                    if had_option {
3366                        wip = wip.end()?; // Close the inner Some value
3367                    }
3368                    wip = wip.end()?; // Close the field itself
3369                }
3370                PathGuard::Variant => {}
3371            }
3372        }
3373
3374        Ok(wip)
3375    }
3376
3377    fn apply_defaults_for_segment(
3378        &mut self,
3379        mut wip: Partial<'input, BORROW>,
3380        segment_name: &str,
3381        defaults_by_first_segment: &mut BTreeMap<&str, Vec<&FieldInfo>>,
3382    ) -> Result<Partial<'input, BORROW>> {
3383        if let Some(entries) = defaults_by_first_segment.remove(segment_name) {
3384            for info in entries {
3385                wip = self.set_missing_field_default(wip, info, true)?;
3386            }
3387        }
3388        Ok(wip)
3389    }
3390
3391    fn apply_default_for_field(
3392        mut wip: Partial<'input, BORROW>,
3393        target_field: &'static facet_core::Field,
3394    ) -> Result<Partial<'input, BORROW>> {
3395        let struct_def = match &wip.shape().ty {
3396            Type::User(UserType::Struct(def)) => def,
3397            _ => {
3398                return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
3399                    message: format!(
3400                        "expected struct while setting default for field '{}'",
3401                        target_field.name
3402                    ),
3403                }));
3404            }
3405        };
3406
3407        let Some(idx) = struct_def
3408            .fields
3409            .iter()
3410            .position(|field| ptr::eq(field, target_field))
3411        else {
3412            return Err(JsonError::without_span(JsonErrorKind::InvalidValue {
3413                message: format!(
3414                    "could not find field '{}' while applying default",
3415                    target_field.name
3416                ),
3417            }));
3418        };
3419
3420        if target_field.has_default() {
3421            wip = wip.set_nth_field_to_default(idx)?;
3422        } else if matches!(target_field.shape().def, Def::Option(_)) {
3423            // Option<T> fields can always default to None.
3424            wip = wip.begin_nth_field(idx)?;
3425            wip = wip.set_default()?;
3426            wip = wip.end()?;
3427        } else {
3428            // Fall back to the field type's Default (this will error if unavailable).
3429            wip = wip.set_nth_field_to_default(idx)?;
3430        }
3431
3432        Ok(wip)
3433    }
3434}
3435
3436#[derive(Debug)]
3437enum PathGuard {
3438    Field { had_option: bool },
3439    Variant,
3440}
3441
3442// ============================================================================
3443// Public API
3444// ============================================================================
3445
3446/// Deserialize JSON from a byte slice into an owned type.
3447///
3448/// This is the recommended default for most use cases. The input does not need
3449/// to outlive the result, making it suitable for deserializing from temporary
3450/// buffers (e.g., HTTP request bodies).
3451///
3452/// Types containing `&str` fields cannot be deserialized with this function;
3453/// use `String` or `Cow<str>` instead. For zero-copy deserialization into
3454/// borrowed types, use [`from_slice_borrowed`].
3455///
3456/// Note: For rich error diagnostics with source code display, prefer [`from_str`]
3457/// which can attach the source string to errors.
3458pub fn from_slice<T: Facet<'static>>(input: &[u8]) -> Result<T> {
3459    from_slice_inner(input, None)
3460}
3461
3462/// Deserialize JSON from a UTF-8 string slice into an owned type.
3463///
3464/// This is the recommended default for most use cases. The input does not need
3465/// to outlive the result, making it suitable for deserializing from temporary
3466/// buffers (e.g., HTTP request bodies).
3467///
3468/// Types containing `&str` fields cannot be deserialized with this function;
3469/// use `String` or `Cow<str>` instead. For zero-copy deserialization into
3470/// borrowed types, use [`from_str_borrowed`].
3471///
3472/// Errors from this function include source code context for rich diagnostic display
3473/// when using [`miette`]'s reporting features.
3474pub fn from_str<T: Facet<'static>>(input: &str) -> Result<T> {
3475    let input_bytes = input.as_bytes();
3476
3477    // Handle BOM
3478    if input_bytes.starts_with(&[0xef, 0xbb, 0xbf]) {
3479        return from_slice_inner(&input_bytes[3..], Some(&input[3..]));
3480    }
3481    from_slice_inner(input_bytes, Some(input))
3482}
3483
3484/// Deserialize JSON from a byte slice, allowing zero-copy borrowing.
3485///
3486/// This variant requires the input to outlive the result (`'input: 'facet`),
3487/// enabling zero-copy deserialization of string fields as `&str`.
3488///
3489/// Use this when you need maximum performance and can guarantee the input
3490/// buffer outlives the deserialized value. For most use cases, prefer
3491/// [`from_slice`] which doesn't have lifetime requirements.
3492///
3493/// Note: For rich error diagnostics with source code display, prefer [`from_str_borrowed`]
3494/// which can attach the source string to errors.
3495pub fn from_slice_borrowed<'input, 'facet, T: Facet<'facet>>(input: &'input [u8]) -> Result<T>
3496where
3497    'input: 'facet,
3498{
3499    from_slice_borrowed_inner(input, None)
3500}
3501
3502/// Deserialize JSON from a UTF-8 string slice, allowing zero-copy borrowing.
3503///
3504/// This variant requires the input to outlive the result (`'input: 'facet`),
3505/// enabling zero-copy deserialization of string fields as `&str`.
3506///
3507/// Use this when you need maximum performance and can guarantee the input
3508/// buffer outlives the deserialized value. For most use cases, prefer
3509/// [`from_str`] which doesn't have lifetime requirements.
3510///
3511/// Errors from this function include source code context for rich diagnostic display
3512/// when using [`miette`]'s reporting features.
3513pub fn from_str_borrowed<'input, 'facet, T: Facet<'facet>>(input: &'input str) -> Result<T>
3514where
3515    'input: 'facet,
3516{
3517    let input_bytes = input.as_bytes();
3518
3519    // Handle BOM
3520    if input_bytes.starts_with(&[0xef, 0xbb, 0xbf]) {
3521        return from_slice_borrowed_inner(&input_bytes[3..], Some(&input[3..]));
3522    }
3523    from_slice_borrowed_inner(input_bytes, Some(input))
3524}
3525
3526fn from_slice_borrowed_inner<'input, 'facet, T: Facet<'facet>>(
3527    input: &'input [u8],
3528    source: Option<&str>,
3529) -> Result<T>
3530where
3531    'input: 'facet,
3532{
3533    let mut deserializer = JsonDeserializer::new(input);
3534    let wip = Partial::alloc::<T>()?;
3535
3536    let partial = match deserializer.deserialize_into(wip) {
3537        Ok(p) => p,
3538        Err(e) => return Err(attach_source_cold(e, source)),
3539    };
3540
3541    // Check that we've consumed all input (no trailing data after the root value)
3542    let trailing = deserializer.peek()?;
3543    if !matches!(trailing.token, Token::Eof) {
3544        let mut err = JsonError::new(
3545            JsonErrorKind::UnexpectedToken {
3546                got: format!("{:?}", trailing.token),
3547                expected: "end of input",
3548            },
3549            trailing.span,
3550        );
3551        if let Some(src) = source {
3552            err.source_code = Some(src.to_string());
3553        }
3554        return Err(err);
3555    }
3556
3557    // Build and materialize the Partial into the target type
3558    let heap_value = match partial.build() {
3559        Ok(v) => v,
3560        Err(e) => return Err(attach_source_cold(JsonError::from(e), source)),
3561    };
3562
3563    match heap_value.materialize::<T>() {
3564        Ok(v) => Ok(v),
3565        Err(e) => Err(attach_source_cold(JsonError::from(e), source)),
3566    }
3567}
3568
3569fn from_slice_inner<T: Facet<'static>>(input: &[u8], source: Option<&str>) -> Result<T> {
3570    // We need to work around the lifetime constraints in the deserialization machinery.
3571    // The deserializer and Partial are parameterized by 'input (the input slice lifetime),
3572    // but we want to produce a T: Facet<'static> that doesn't borrow from input.
3573    //
3574    // The approach: Use an inner function parameterized by 'input that does all the work,
3575    // then transmute the result back to the 'static lifetime we need.
3576    //
3577    // SAFETY: This is safe because:
3578    // 1. T: Facet<'static> guarantees the type T itself contains no borrowed data
3579    // 2. allow_borrow: false ensures we error before storing any borrowed references
3580    // 3. BORROW: false on Partial/HeapValue documents that no borrowing occurs
3581    // 4. The transmutes only affect phantom lifetime markers, not actual runtime data
3582
3583    fn inner<'input, T: Facet<'static>>(input: &'input [u8], source: Option<&str>) -> Result<T> {
3584        let mut deserializer = JsonDeserializer::new_owned(input);
3585
3586        // Allocate a Partial<'static, false> - owned mode, no borrowing allowed.
3587        // We transmute to Partial<'input, false> to work with the deserializer.
3588        // SAFETY: We're only changing the lifetime marker. The Partial<_, false> doesn't
3589        // store any 'input references because:
3590        // - BORROW=false documents no borrowed data
3591        // - allow_borrow=false on deserializer prevents runtime borrowing
3592        #[allow(unsafe_code)]
3593        let wip: Partial<'input, false> = unsafe {
3594            core::mem::transmute::<Partial<'static, false>, Partial<'input, false>>(
3595                Partial::alloc_owned::<T>()?,
3596            )
3597        };
3598
3599        let partial = match deserializer.deserialize_into(wip) {
3600            Ok(p) => p,
3601            Err(e) => return Err(attach_source_cold(e, source)),
3602        };
3603
3604        // Check that we've consumed all input (no trailing data after the root value)
3605        let trailing = deserializer.peek()?;
3606        if !matches!(trailing.token, Token::Eof) {
3607            let mut err = JsonError::new(
3608                JsonErrorKind::UnexpectedToken {
3609                    got: format!("{:?}", trailing.token),
3610                    expected: "end of input",
3611                },
3612                trailing.span,
3613            );
3614            if let Some(src) = source {
3615                err.source_code = Some(src.to_string());
3616            }
3617            return Err(err);
3618        }
3619
3620        // Build the Partial into a HeapValue
3621        let heap_value = match partial.build() {
3622            Ok(v) => v,
3623            Err(e) => return Err(attach_source_cold(JsonError::from(e), source)),
3624        };
3625
3626        // Transmute HeapValue<'input, false> to HeapValue<'static, false> so we can materialize to T
3627        // SAFETY: The HeapValue contains no borrowed data:
3628        // - BORROW=false documents no borrowed data
3629        // - allow_borrow=false ensured this at runtime
3630        // The transmute only affects the phantom lifetime marker.
3631        #[allow(unsafe_code)]
3632        let heap_value: facet_reflect::HeapValue<'static, false> = unsafe {
3633            core::mem::transmute::<
3634                facet_reflect::HeapValue<'input, false>,
3635                facet_reflect::HeapValue<'static, false>,
3636            >(heap_value)
3637        };
3638
3639        match heap_value.materialize::<T>() {
3640            Ok(v) => Ok(v),
3641            Err(e) => Err(attach_source_cold(JsonError::from(e), source)),
3642        }
3643    }
3644
3645    inner::<T>(input, source)
3646}