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