facet_deserialize/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![warn(missing_docs)]
3#![warn(clippy::std_instead_of_core)]
4#![warn(clippy::std_instead_of_alloc)]
5#![deny(unsafe_code)]
6#![doc = include_str!("../README.md")]
7
8extern crate alloc;
9
10use alloc::string::ToString;
11use alloc::{vec, vec::Vec};
12use core::fmt::Debug;
13
14mod debug;
15mod error;
16use alloc::borrow::Cow;
17pub use debug::InputDebug;
18
19pub use error::*;
20
21mod span;
22use facet_core::{
23    Characteristic, Def, Facet, FieldFlags, PointerType, ScalarAffinity, SequenceType, StructKind,
24    Type, UserType,
25};
26use owo_colors::OwoColorize;
27pub use span::*;
28
29use facet_reflect::{HeapValue, ReflectError, Wip};
30use log::trace;
31
32#[derive(PartialEq, Debug, Clone)]
33/// A scalar value used during deserialization.
34/// `u64` and `i64` are separated because `i64` doesn't fit in `u64`,
35/// but having `u64` is a fast path for 64-bit architectures — no need to
36/// go through `u128` / `i128` for everything
37pub enum Scalar<'input> {
38    /// Owned or borrowed string data.
39    String(Cow<'input, str>),
40    /// Unsigned 64-bit integer scalar.
41    U64(u64),
42    /// Signed 64-bit integer scalar.
43    I64(i64),
44    /// 64-bit floating-point scalar.
45    F64(f64),
46    /// Boolean scalar.
47    Bool(bool),
48    /// Null scalar (e.g. for formats supporting explicit null).
49    Null,
50}
51
52#[derive(PartialEq, Debug, Clone)]
53/// Expected next input token or structure during deserialization.
54pub enum Expectation {
55    /// Accept a value.
56    Value,
57    /// Expect an object key or the end of an object.
58    ObjectKeyOrObjectClose,
59    /// Expect a value inside an object.
60    ObjectVal,
61    /// Expect a list item or the end of a list.
62    ListItemOrListClose,
63}
64
65#[derive(PartialEq, Debug, Clone)]
66/// Outcome of parsing the next input element.
67pub enum Outcome<'input> {
68    /// Parsed a scalar value.
69    Scalar(Scalar<'input>),
70    /// Starting a list/array.
71    ListStarted,
72    /// Ending a list/array.
73    ListEnded,
74    /// Starting an object/map.
75    ObjectStarted,
76    /// Ending an object/map.
77    ObjectEnded,
78    /// Resegmenting input into subspans.
79    Resegmented(Vec<Subspan>),
80}
81
82impl<'input> From<Scalar<'input>> for Outcome<'input> {
83    fn from(scalar: Scalar<'input>) -> Self {
84        Outcome::Scalar(scalar)
85    }
86}
87
88use core::fmt;
89
90/// Display implementation for `Outcome`, focusing on user-friendly descriptions.
91impl fmt::Display for Outcome<'_> {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        match self {
94            Outcome::Scalar(scalar) => write!(f, "scalar {}", scalar),
95            Outcome::ListStarted => write!(f, "list start"),
96            Outcome::ListEnded => write!(f, "list end"),
97            Outcome::ObjectStarted => write!(f, "object start"),
98            Outcome::ObjectEnded => write!(f, "object end"),
99            Outcome::Resegmented(_) => write!(f, "resegment"),
100        }
101    }
102}
103
104/// Display implementation for `Scalar`, for use in displaying `Outcome`.
105impl fmt::Display for Scalar<'_> {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        match self {
108            Scalar::String(s) => write!(f, "string \"{}\"", s),
109            Scalar::U64(val) => write!(f, "u64 {}", val),
110            Scalar::I64(val) => write!(f, "i64 {}", val),
111            Scalar::F64(val) => write!(f, "f64 {}", val),
112            Scalar::Bool(val) => write!(f, "bool {}", val),
113            Scalar::Null => write!(f, "null"),
114        }
115    }
116}
117
118impl Outcome<'_> {
119    fn into_owned(self) -> Outcome<'static> {
120        match self {
121            Outcome::Scalar(scalar) => {
122                let owned_scalar = match scalar {
123                    Scalar::String(cow) => Scalar::String(Cow::Owned(cow.into_owned())),
124                    Scalar::U64(val) => Scalar::U64(val),
125                    Scalar::I64(val) => Scalar::I64(val),
126                    Scalar::F64(val) => Scalar::F64(val),
127                    Scalar::Bool(val) => Scalar::Bool(val),
128                    Scalar::Null => Scalar::Null,
129                };
130                Outcome::Scalar(owned_scalar)
131            }
132            Outcome::ListStarted => Outcome::ListStarted,
133            Outcome::ListEnded => Outcome::ListEnded,
134            Outcome::ObjectStarted => Outcome::ObjectStarted,
135            Outcome::ObjectEnded => Outcome::ObjectEnded,
136            Outcome::Resegmented(subspans) => {
137                let owned_subspans = subspans
138                    .into_iter()
139                    .map(|s| Subspan {
140                        offset: s.offset,
141                        len: s.len,
142                        meta: s.meta,
143                    })
144                    .collect();
145                Outcome::Resegmented(owned_subspans)
146            }
147        }
148    }
149}
150
151/// Carries the current parsing state and the in-progress value during deserialization.
152/// This bundles the mutable context that must be threaded through parsing steps.
153pub struct NextData<'input, 'facet, 'shape, C = Cooked, I = [u8]>
154where
155    'input: 'facet,
156    I: ?Sized + 'input,
157{
158    /// The offset we're supposed to start parsing from
159    start: usize,
160
161    /// Controls the parsing flow and stack state.
162    runner: StackRunner<'input, C, I>,
163
164    /// Holds the intermediate representation of the value being built.
165    pub wip: Wip<'facet, 'shape>,
166}
167
168impl<'input, 'facet, 'shape, C, I> NextData<'input, 'facet, 'shape, C, I>
169where
170    'input: 'facet,
171    I: ?Sized + 'input,
172{
173    /// Returns the input (from the start! not from the current position)
174    pub fn input(&self) -> &'input I {
175        self.runner.input
176    }
177
178    /// Returns the parsing start offset.
179    pub fn start(&self) -> usize {
180        self.start
181    }
182
183    /// Access the substack
184    pub fn substack(&self) -> &Substack<C> {
185        &self.runner.substack
186    }
187}
188
189/// The result of advancing the parser: updated state and parse outcome or error.
190pub type NextResult<'input, 'facet, 'shape, T, E, C, I = [u8]> =
191    (NextData<'input, 'facet, 'shape, C, I>, Result<T, E>);
192
193/// Trait defining a deserialization format.
194/// Provides the next parsing step based on current state and expected input.
195pub trait Format {
196    /// The kind of input this format consumes, parameterized by input lifetime.
197    ///
198    /// * `JsonFmt` => `Input<'input> = [u8]`
199    /// * `CliFmt`  => `Input<'input> = [&'input str]`
200    type Input<'input>: ?Sized;
201
202    /// The type of span used by this format (Raw or Cooked)
203    type SpanType: Debug + SubstackBehavior + 'static;
204
205    /// The lowercase source ID of the format, used for error reporting.
206    fn source(&self) -> &'static str;
207
208    /// Advance the parser with current state and expectation, producing the next outcome or error.
209    #[allow(clippy::type_complexity)]
210    fn next<'input, 'facet, 'shape>(
211        &mut self,
212        nd: NextData<'input, 'facet, 'shape, Self::SpanType, Self::Input<'input>>,
213        expectation: Expectation,
214    ) -> NextResult<
215        'input,
216        'facet,
217        'shape,
218        Spanned<Outcome<'input>, Self::SpanType>,
219        Spanned<DeserErrorKind<'shape>, Self::SpanType>,
220        Self::SpanType,
221        Self::Input<'input>,
222    >
223    where
224        'shape: 'input;
225
226    /// Skip the next value; used to ignore an input.
227    #[allow(clippy::type_complexity)]
228    fn skip<'input, 'facet, 'shape>(
229        &mut self,
230        nd: NextData<'input, 'facet, 'shape, Self::SpanType, Self::Input<'input>>,
231    ) -> NextResult<
232        'input,
233        'facet,
234        'shape,
235        Span<Self::SpanType>,
236        Spanned<DeserErrorKind<'shape>, Self::SpanType>,
237        Self::SpanType,
238        Self::Input<'input>,
239    >
240    where
241        'shape: 'input;
242}
243
244/// Trait handling conversion regardless of `Format::SpanType` to `Span<Cooked>`
245pub trait ToCooked<'input, F: Format> {
246    /// Convert a span to a Cooked span (with byte index over the input, not format-specific index)
247    fn to_cooked(self, format: &F, input: &'input F::Input<'input>) -> Span<Cooked>;
248}
249
250impl<'input, F: Format> ToCooked<'input, F> for Span<Cooked> {
251    #[inline]
252    fn to_cooked(self, _format: &F, _input: &'input F::Input<'input>) -> Span<Cooked> {
253        self
254    }
255}
256
257impl<'input, F: Format<SpanType = Raw, Input<'input> = [&'input str]>> ToCooked<'input, F>
258    for Span<Raw>
259{
260    #[inline]
261    fn to_cooked(self, _format: &F, input: &'input [&'input str]) -> Span<Cooked> {
262        if self.start >= input.len() {
263            // start points past the end of the args;
264            // use byte offset = total length of whole input minus 1, len = 1
265            let mut total_len = 0;
266            for (i, arg) in input.iter().enumerate() {
267                total_len += arg.len();
268                if i < input.len() - 1 {
269                    total_len += 1; // space after each arg except last
270                }
271            }
272            return Span::<Cooked>::new(total_len.saturating_sub(1), 1);
273        }
274
275        // Calculate start position by summing lengths of preceding args plus spaces
276        let mut start = 0;
277        for arg in input.iter().take(self.start) {
278            start += arg.len() + 1; // +1 for space between args
279        }
280
281        // Length is the length of the current arg
282        let len = input[self.start].len();
283
284        Span::<Cooked>::new(start, len)
285    }
286}
287
288/// Instructions guiding the parsing flow, indicating the next expected action or token.
289#[derive(Debug, Clone, Copy, PartialEq, Eq)]
290pub enum Instruction {
291    /// Expect a value, specifying the context or reason.
292    Value(ValueReason),
293    /// Skip the next value; used to ignore an input.
294    SkipValue,
295    /// Indicate completion of a structure or value; triggers popping from stack.
296    Pop(PopReason),
297    /// Expect an object key or the end of an object.
298    ObjectKeyOrObjectClose,
299    /// Expect a list item or the end of a list.
300    ListItemOrListClose,
301    /// Triggers clearing a substack.
302    SubstackClose,
303}
304
305/// Reasons for expecting a value, reflecting the current parse context.
306#[derive(Debug, Clone, Copy, PartialEq, Eq)]
307pub enum ValueReason {
308    /// Parsing at the root level.
309    TopLevel,
310    /// Parsing a value inside an object.
311    ObjectVal,
312}
313
314/// Reasons for popping a state from the stack, indicating why a scope is ended.
315#[derive(Debug, Clone, Copy, PartialEq, Eq)]
316pub enum PopReason {
317    /// Ending the top-level parsing scope.
318    TopLevel,
319    /// Ending a value within an object.
320    ObjectVal,
321    /// Ending value within a list
322    ListVal,
323    /// Ending a `Some()` in an option
324    Some,
325    /// Ending a smart pointer (ie. wrapping a `T` back into a `Box<T>`, or `Arc<T>` etc.)
326    SmartPointer,
327    /// Ending a wrapper value such as a newtype
328    Wrapper,
329}
330
331mod deser_impl {
332    use super::*;
333
334    /// Deserialize a value of type `T` from raw input bytes using format `F`.
335    ///
336    /// This function sets up the initial working state and drives the deserialization process,
337    /// ensuring that the resulting value is fully materialized and valid.
338    pub fn deserialize<'input, 'facet, 'shape, T, F>(
339        input: &'input F::Input<'input>,
340        format: &mut F,
341    ) -> Result<T, DeserError<'input, 'shape, Cooked>>
342    where
343        T: Facet<'facet>,
344        F: Format + 'shape,
345        F::Input<'input>: InputDebug,
346        F::SpanType: core::fmt::Debug,
347        Span<F::SpanType>: ToCooked<'input, F>,
348        'input: 'facet,
349        'shape: 'input,
350    {
351        // Run the entire deserialization process and capture any errors
352        let result: Result<T, DeserError<'input, 'shape, Cooked>> = {
353            let source = format.source();
354
355            // Step 1: Allocate shape
356            let wip = match Wip::alloc_shape(T::SHAPE) {
357                Ok(wip) => wip,
358                Err(e) => {
359                    let default_span = Span::<F::SpanType>::default();
360                    // let cooked_span = cook_span_dispatch!(format, default_span, input);
361                    let cooked_span = default_span.to_cooked(format, input);
362                    return Err(DeserError::new_reflect(e, input, cooked_span, source));
363                }
364            };
365
366            // Step 2: Run deserialize_wip
367            let heap_value = match deserialize_wip(wip, input, format) {
368                Ok(val) => val,
369                Err(e) => {
370                    let cooked_span = e.span.to_cooked(format, input);
371
372                    // Create a completely new error variable with the Cooked type
373                    let cooked_error = DeserError {
374                        input: e.input,
375                        span: cooked_span,
376                        kind: e.kind,
377                        source_id: e.source_id,
378                    };
379
380                    return Err(cooked_error);
381                }
382            };
383
384            // Step 3: Materialize
385            match heap_value.materialize() {
386                Ok(val) => Ok(val),
387                Err(e) => {
388                    let default_span = Span::<F::SpanType>::default();
389                    let cooked_span = default_span.to_cooked(format, input);
390                    return Err(DeserError::new_reflect(e, input, cooked_span, source));
391                }
392            }
393        };
394
395        // Apply span conversion for errors from materialization
396        match result {
397            Ok(value) => Ok(value),
398            Err(mut error) => {
399                let new_span = error.span.to_cooked(format, input);
400
401                if new_span != error.span {
402                    error = DeserError {
403                        input: error.input,
404                        span: new_span,
405                        kind: error.kind,
406                        source_id: error.source_id,
407                    };
408                }
409
410                Err(error)
411            }
412        }
413    }
414}
415
416/// Deserialize a value of type `T` from raw input bytes using format `F`.
417///
418/// This function sets up the initial working state and drives the deserialization process,
419/// ensuring that the resulting value is fully materialized and valid.
420pub fn deserialize<'input, 'facet, 'shape, T, F>(
421    input: &'input F::Input<'input>,
422    format: F,
423) -> Result<T, DeserError<'input, 'shape, Cooked>>
424where
425    T: Facet<'facet>,
426    F: Format + 'shape,
427    F::Input<'input>: InputDebug,
428    F::SpanType: core::fmt::Debug,
429    Span<F::SpanType>: ToCooked<'input, F>,
430    'input: 'facet,
431    'shape: 'input,
432{
433    let mut format_copy = format;
434    deser_impl::deserialize(input, &mut format_copy)
435}
436
437/// Deserializes a working-in-progress value into a fully materialized heap value.
438/// This function drives the parsing loop until the entire input is consumed and the value is complete.
439pub fn deserialize_wip<'input, 'facet, 'shape, F>(
440    mut wip: Wip<'facet, 'shape>,
441    input: &'input F::Input<'input>,
442    format: &mut F,
443) -> Result<HeapValue<'facet, 'shape>, DeserError<'input, 'shape, Cooked>>
444where
445    F: Format + 'shape,
446    F::SpanType: SubstackBehavior,
447    F::Input<'input>: InputDebug,
448    Span<F::SpanType>: ToCooked<'input, F>,
449    'input: 'facet,
450    'shape: 'input,
451{
452    // This struct is just a bundle of the state that we need to pass around all the time.
453    let mut runner = StackRunner {
454        original_input: input,
455        input,
456        stack: vec![
457            Instruction::Pop(PopReason::TopLevel),
458            Instruction::Value(ValueReason::TopLevel),
459        ],
460        substack: Substack::new(),
461        last_span: Span::new(0, 0),
462        format_source: format.source(),
463    };
464
465    macro_rules! next {
466        ($runner:ident, $wip:ident, $expectation:expr, $method:ident) => {{
467            let nd = NextData {
468                start: $runner.last_span.end(), // or supply the appropriate start value if available
469                runner: $runner,
470                wip: $wip,
471            };
472            let (nd, res) = format.next(nd, $expectation);
473            $runner = nd.runner;
474            $wip = nd.wip;
475            let outcome = res.map_err(|span_kind| {
476                $runner.last_span = span_kind.span;
477                let error = $runner.err(span_kind.node);
478                // Convert the error's span to Cooked
479                DeserError {
480                    input: error.input,
481                    span: error.span.to_cooked(format, input),
482                    kind: error.kind,
483                    source_id: error.source_id,
484                }
485            })?;
486            if F::SpanType::USES_SUBSTACK {
487                if !$runner.substack.get().is_empty() {
488                    trace!("Substack: {}", "carried".cyan());
489                } else {
490                    trace!("Substack: {}", "-".red());
491                }
492            }
493            $runner.last_span = outcome.span;
494            if F::SpanType::USES_SUBSTACK {
495                if let Outcome::Resegmented(subspans) = &outcome.node {
496                    $runner.substack = subspans.clone().into();
497                }
498            }
499            $wip = $runner.$method($wip, outcome).map_err(|error| {
500                DeserError {
501                    input:  error.input,
502                    span:   error.span.to_cooked(format, input),
503                    kind:   error.kind,
504                    source_id: error.source_id,
505                }
506            })?;
507        }};
508    }
509
510    loop {
511        let frame_count = wip.frames_count();
512        debug_assert!(
513            frame_count
514                >= runner
515                    .stack
516                    .iter()
517                    .filter(|f| matches!(f, Instruction::Pop(_)))
518                    .count()
519        );
520
521        let insn = match runner.stack.pop() {
522            Some(insn) => insn,
523            None => unreachable!("Instruction stack is empty"),
524        };
525
526        trace!("[{frame_count}] Instruction {:?}", insn.bright_red());
527
528        match insn {
529            Instruction::Pop(reason) => {
530                wip = runner.pop(wip, reason).map_err(|error| {
531                    // Convert the error's span to Cooked
532                    DeserError {
533                        input: error.input,
534                        span: error.span.to_cooked(format, input),
535                        kind: error.kind,
536                        source_id: error.source_id,
537                    }
538                })?;
539
540                if reason == PopReason::TopLevel {
541                    return wip.build().map_err(|e| {
542                        let reflect_error = runner.reflect_err(e);
543                        // Convert the reflection error's span to Cooked
544                        DeserError {
545                            input: reflect_error.input,
546                            span: reflect_error.span.to_cooked(format, input),
547                            kind: reflect_error.kind,
548                            source_id: reflect_error.source_id,
549                        }
550                    });
551                } else {
552                    wip = wip.pop().map_err(|e| {
553                        let reflect_error = runner.reflect_err(e);
554                        // Convert the reflection error's span to Cooked
555                        DeserError {
556                            input: reflect_error.input,
557                            span: reflect_error.span.to_cooked(format, input),
558                            kind: reflect_error.kind,
559                            source_id: reflect_error.source_id,
560                        }
561                    })?;
562                }
563            }
564            Instruction::Value(_why) => {
565                let expectation = match _why {
566                    ValueReason::TopLevel => Expectation::Value,
567                    ValueReason::ObjectVal => Expectation::ObjectVal,
568                };
569                next!(runner, wip, expectation, value);
570            }
571            Instruction::ObjectKeyOrObjectClose => {
572                next!(
573                    runner,
574                    wip,
575                    Expectation::ObjectKeyOrObjectClose,
576                    object_key_or_object_close
577                );
578            }
579            Instruction::ListItemOrListClose => {
580                next!(
581                    runner,
582                    wip,
583                    Expectation::ListItemOrListClose,
584                    list_item_or_list_close
585                );
586            }
587            Instruction::SubstackClose => {
588                runner.substack.clear();
589            }
590            Instruction::SkipValue => {
591                // Call F::skip to skip over the next value in the input
592                let nd = NextData {
593                    start: runner.last_span.end(),
594                    runner,
595                    wip,
596                };
597                let (nd, res) = format.skip(nd);
598                runner = nd.runner;
599                wip = nd.wip;
600                // Only propagate error, don't modify wip, since skip just advances input
601                let span = res.map_err(|span_kind| {
602                    runner.last_span = span_kind.span;
603                    let error = runner.err(span_kind.node);
604                    // Convert the error's span to Cooked
605                    DeserError {
606                        input: error.input,
607                        span: error.span.to_cooked(format, input),
608                        kind: error.kind,
609                        source_id: error.source_id,
610                    }
611                })?;
612                // do the actual skip
613                runner.last_span = span;
614            }
615        }
616    }
617}
618
619#[doc(hidden)]
620/// Maintains the parsing state and context necessary to drive deserialization.
621///
622/// This struct tracks what the parser expects next, manages input position,
623/// and remembers the span of the last processed token to provide accurate error reporting.
624pub struct StackRunner<'input, C = Cooked, I: ?Sized + 'input = [u8]> {
625    /// A version of the input that doesn't advance as we parse.
626    pub original_input: &'input I,
627
628    /// The raw input data being deserialized.
629    pub input: &'input I,
630
631    /// Stack of parsing instructions guiding the control flow.
632    pub stack: Vec<Instruction>,
633
634    /// Subspan storage, if the format uses them.
635    pub substack: Substack<C>,
636
637    /// Span of the last processed token, for accurate error reporting.
638    pub last_span: Span<C>,
639
640    /// Format source identifier for error reporting
641    pub format_source: &'static str,
642}
643
644impl<'input, 'shape, C, I: ?Sized + 'input> StackRunner<'input, C, I>
645where
646    I: InputDebug,
647{
648    /// Convenience function to create a DeserError using the original input and last_span.
649    fn err(&self, kind: DeserErrorKind<'shape>) -> DeserError<'input, 'shape, C> {
650        DeserError::new(
651            kind,
652            self.original_input,
653            self.last_span,
654            self.format_source,
655        )
656    }
657
658    /// Convenience function to create a DeserError from a ReflectError,
659    /// using the original input and last_span for context.
660    fn reflect_err(&self, err: ReflectError<'shape>) -> DeserError<'input, 'shape, C> {
661        DeserError::new_reflect(err, self.original_input, self.last_span, self.format_source)
662    }
663
664    pub fn pop<'facet>(
665        &mut self,
666        mut wip: Wip<'facet, 'shape>,
667        reason: PopReason,
668    ) -> Result<Wip<'facet, 'shape>, DeserError<'input, 'shape, C>> {
669        trace!(
670            "--- STACK has {:?} {}",
671            self.stack.green(),
672            "(POP)".bright_yellow()
673        );
674        trace!("Popping because {:?}", reason.yellow());
675
676        let container_shape = wip.shape();
677        match container_shape.ty {
678            Type::User(UserType::Struct(sd)) => {
679                let mut has_unset = false;
680
681                trace!("Let's check all fields are initialized");
682                for (index, field) in sd.fields.iter().enumerate() {
683                    let is_set = wip.is_field_set(index).map_err(|err| {
684                        trace!("Error checking field set status: {:?}", err);
685                        self.reflect_err(err)
686                    })?;
687                    if !is_set {
688                        if field.flags.contains(FieldFlags::DEFAULT) {
689                            wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
690                            if let Some(default_in_place_fn) = field.vtable.default_fn {
691                                wip = wip
692                                    .put_from_fn(default_in_place_fn)
693                                    .map_err(|e| self.reflect_err(e))?;
694                                trace!(
695                                    "Field #{} {} @ {} was set to default value (via custom fn)",
696                                    index.yellow(),
697                                    field.name.green(),
698                                    field.offset.blue(),
699                                );
700                            } else {
701                                if !field.shape().is(Characteristic::Default) {
702                                    return Err(self.reflect_err(
703                                        ReflectError::DefaultAttrButNoDefaultImpl {
704                                            shape: field.shape(),
705                                        },
706                                    ));
707                                }
708                                wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
709                                trace!(
710                                    "Field #{} {} @ {} was set to default value (via default impl)",
711                                    index.yellow(),
712                                    field.name.green(),
713                                    field.offset.blue(),
714                                );
715                            }
716                            wip = wip.pop().map_err(|e| self.reflect_err(e))?;
717                        } else {
718                            trace!(
719                                "Field #{} {} @ {} is not initialized",
720                                index.yellow(),
721                                field.name.green(),
722                                field.offset.blue(),
723                            );
724                            has_unset = true;
725                        }
726                    }
727                }
728
729                if has_unset && container_shape.has_default_attr() {
730                    // let's allocate and build a default value
731                    let default_val = Wip::alloc_shape(container_shape)
732                        .map_err(|e| self.reflect_err(e))?
733                        .put_default()
734                        .map_err(|e| self.reflect_err(e))?
735                        .build()
736                        .map_err(|e| self.reflect_err(e))?;
737                    let peek = default_val.peek().into_struct().unwrap();
738
739                    for (index, field) in sd.fields.iter().enumerate() {
740                        let is_set = wip.is_field_set(index).map_err(|err| {
741                            trace!("Error checking field set status: {:?}", err);
742                            self.reflect_err(err)
743                        })?;
744                        if !is_set {
745                            let address_of_field_from_default = peek.field(index).unwrap().data();
746                            wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
747                            wip = wip
748                                .put_shape(address_of_field_from_default, field.shape())
749                                .map_err(|e| self.reflect_err(e))?;
750                            wip = wip.pop().map_err(|e| self.reflect_err(e))?;
751                        }
752                    }
753                }
754            }
755            Type::User(UserType::Enum(ed)) => {
756                trace!("Checking if enum is initialized correctly");
757
758                // Check if a variant has been selected
759                if let Some(variant) = wip.selected_variant() {
760                    trace!("Variant {} is selected", variant.name.blue());
761
762                    // Check if all fields in the variant are initialized
763                    if !variant.data.fields.is_empty() {
764                        let mut has_unset = false;
765
766                        for (index, field) in variant.data.fields.iter().enumerate() {
767                            let is_set = wip.is_field_set(index).map_err(|err| {
768                                trace!("Error checking field set status: {:?}", err);
769                                self.reflect_err(err)
770                            })?;
771
772                            if !is_set {
773                                if field.flags.contains(FieldFlags::DEFAULT) {
774                                    wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
775                                    if let Some(default_in_place_fn) = field.vtable.default_fn {
776                                        wip = wip
777                                            .put_from_fn(default_in_place_fn)
778                                            .map_err(|e| self.reflect_err(e))?;
779                                        trace!(
780                                            "Field #{} @ {} in variant {} was set to default value (via custom fn)",
781                                            index.yellow(),
782                                            field.offset.blue(),
783                                            variant.name
784                                        );
785                                    } else {
786                                        if !field.shape().is(Characteristic::Default) {
787                                            return Err(self.reflect_err(
788                                                ReflectError::DefaultAttrButNoDefaultImpl {
789                                                    shape: field.shape(),
790                                                },
791                                            ));
792                                        }
793                                        wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
794                                        trace!(
795                                            "Field #{} @ {} in variant {} was set to default value (via default impl)",
796                                            index.yellow(),
797                                            field.offset.blue(),
798                                            variant.name
799                                        );
800                                    }
801                                    wip = wip.pop().map_err(|e| self.reflect_err(e))?;
802                                } else {
803                                    trace!(
804                                        "Field #{} @ {} in variant {} is not initialized",
805                                        index.yellow(),
806                                        field.offset.blue(),
807                                        variant.name
808                                    );
809                                    has_unset = true;
810                                }
811                            }
812                        }
813
814                        if has_unset && container_shape.has_default_attr() {
815                            trace!("Enum has DEFAULT attr but variant has uninitialized fields");
816                            // Handle similar to struct, allocate and build default value for variant
817                            let default_val = Wip::alloc_shape(container_shape)
818                                .map_err(|e| self.reflect_err(e))?
819                                .put_default()
820                                .map_err(|e| self.reflect_err(e))?
821                                .build()
822                                .map_err(|e| self.reflect_err(e))?;
823
824                            let peek = default_val.peek();
825                            let peek_enum = peek.into_enum().map_err(|e| self.reflect_err(e))?;
826                            let default_variant = peek_enum
827                                .active_variant()
828                                .map_err(|e| self.err(DeserErrorKind::VariantError(e)))?;
829
830                            if default_variant == &variant {
831                                // It's the same variant, fill in the missing fields
832                                for (index, field) in variant.data.fields.iter().enumerate() {
833                                    let is_set = wip.is_field_set(index).map_err(|err| {
834                                        trace!("Error checking field set status: {:?}", err);
835                                        self.reflect_err(err)
836                                    })?;
837                                    if !is_set {
838                                        if let Ok(Some(def_field)) = peek_enum.field(index) {
839                                            wip = wip
840                                                .field(index)
841                                                .map_err(|e| self.reflect_err(e))?;
842                                            wip = wip
843                                                .put_shape(def_field.data(), field.shape())
844                                                .map_err(|e| self.reflect_err(e))?;
845                                            wip = wip.pop().map_err(|e| self.reflect_err(e))?;
846                                        }
847                                    }
848                                }
849                            }
850                        }
851                    }
852                } else if container_shape.has_default_attr() {
853                    // No variant selected, but enum has default attribute - set to default
854                    trace!("No variant selected but enum has DEFAULT attr; setting to default");
855                    let default_val = Wip::alloc_shape(container_shape)
856                        .map_err(|e| self.reflect_err(e))?
857                        .put_default()
858                        .map_err(|e| self.reflect_err(e))?
859                        .build()
860                        .map_err(|e| self.reflect_err(e))?;
861
862                    let peek = default_val.peek();
863                    let peek_enum = peek.into_enum().map_err(|e| self.reflect_err(e))?;
864                    let default_variant_idx = peek_enum
865                        .variant_index()
866                        .map_err(|e| self.err(DeserErrorKind::VariantError(e)))?;
867
868                    // Select the default variant
869                    wip = wip
870                        .variant(default_variant_idx)
871                        .map_err(|e| self.reflect_err(e))?;
872
873                    // Copy all fields from default value
874                    let variant = &ed.variants[default_variant_idx];
875                    for (index, field) in variant.data.fields.iter().enumerate() {
876                        if let Ok(Some(def_field)) = peek_enum.field(index) {
877                            wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
878                            wip = wip
879                                .put_shape(def_field.data(), field.shape())
880                                .map_err(|e| self.reflect_err(e))?;
881                            wip = wip.pop().map_err(|e| self.reflect_err(e))?;
882                        }
883                    }
884                }
885            }
886            _ => {
887                trace!(
888                    "Thing being popped is not a container I guess (it's a {}, innermost is {})",
889                    wip.shape(),
890                    wip.innermost_shape()
891                );
892            }
893        }
894        Ok(wip)
895    }
896
897    /// Internal common handler for GotScalar outcome, to deduplicate code.
898    fn handle_scalar<'facet>(
899        &self,
900        wip: Wip<'facet, 'shape>,
901        scalar: Scalar<'input>,
902    ) -> Result<Wip<'facet, 'shape>, DeserError<'input, 'shape, C>>
903    where
904        'input: 'facet, // 'input outlives 'facet
905    {
906        match scalar {
907            Scalar::String(cow) => {
908                match wip.innermost_shape().ty {
909                    Type::User(UserType::Enum(_)) => {
910                        if wip.selected_variant().is_some() {
911                            // If we already have a variant selected, just put the string
912                            wip.put(cow.to_string()).map_err(|e| self.reflect_err(e))
913                        } else {
914                            // Try to select the variant
915                            match wip.find_variant(&cow) {
916                                Some((variant_index, _)) => {
917                                    wip.variant(variant_index).map_err(|e| self.reflect_err(e))
918                                }
919                                None => Err(self.err(DeserErrorKind::NoSuchVariant {
920                                    name: cow.to_string(),
921                                    enum_shape: wip.innermost_shape(),
922                                })),
923                            }
924                        }
925                    }
926                    Type::Pointer(PointerType::Reference(_))
927                        if wip.innermost_shape().is_type::<&str>() =>
928                    {
929                        // This is for handling the &str type
930                        // The Cow may be Borrowed (we may have an owned string but need a &str)
931                        match cow {
932                            Cow::Borrowed(s) => wip.put(s).map_err(|e| self.reflect_err(e)),
933                            Cow::Owned(s) => wip.put(s).map_err(|e| self.reflect_err(e)),
934                        }
935                    }
936                    _ => wip.put(cow.to_string()).map_err(|e| self.reflect_err(e)),
937                }
938            }
939            Scalar::U64(value) => wip.put(value).map_err(|e| self.reflect_err(e)),
940            Scalar::I64(value) => wip.put(value).map_err(|e| self.reflect_err(e)),
941            Scalar::F64(value) => wip.put(value).map_err(|e| self.reflect_err(e)),
942            Scalar::Bool(value) => wip.put(value).map_err(|e| self.reflect_err(e)),
943            Scalar::Null => wip.put_default().map_err(|e| self.reflect_err(e)),
944        }
945    }
946
947    /// Handle value parsing
948    fn value<'facet>(
949        &mut self,
950        mut wip: Wip<'facet, 'shape>,
951        outcome: Spanned<Outcome<'input>, C>,
952    ) -> Result<Wip<'facet, 'shape>, DeserError<'input, 'shape, C>>
953    where
954        'input: 'facet, // 'input must outlive 'facet
955    {
956        trace!(
957            "--- STACK has {:?} {}",
958            self.stack.green(),
959            "(VALUE)".bright_yellow()
960        );
961
962        let original_shape = wip.shape();
963        trace!("Handling value of type {}", original_shape.blue());
964
965        // Handle null values
966        if matches!(outcome.node, Outcome::Scalar(Scalar::Null)) {
967            return wip.put_default().map_err(|e| self.reflect_err(e));
968        }
969
970        // Resolve the innermost value to deserialize
971        loop {
972            if matches!(wip.shape().def, Def::Option(_)) {
973                trace!("  Starting Some(_) option for {}", wip.shape().blue());
974                wip = wip.push_some().map_err(|e| self.reflect_err(e))?;
975                self.stack.push(Instruction::Pop(PopReason::Some));
976            } else if let Def::SmartPointer(inner) = wip.shape().def {
977                if let Some(pointee) = inner.pointee() {
978                    trace!(
979                        "  Starting smart pointer for {} (pointee is {})",
980                        wip.shape().blue(),
981                        pointee.yellow(),
982                    );
983                } else {
984                    trace!(
985                        "  Starting smart pointer for {} (no pointee)",
986                        wip.shape().blue()
987                    );
988                }
989                wip = wip.push_pointee().map_err(|e| self.reflect_err(e))?;
990                self.stack.push(Instruction::Pop(PopReason::SmartPointer));
991            } else if let Some(inner_fn) = wip.shape().inner {
992                let inner = inner_fn();
993                trace!(
994                    "  Starting wrapped value for {} (inner is {})",
995                    wip.shape().blue(),
996                    inner.yellow()
997                );
998                wip = wip.push_inner().map_err(|e| self.reflect_err(e))?;
999                self.stack.push(Instruction::Pop(PopReason::Wrapper));
1000            } else {
1001                break;
1002            }
1003        }
1004
1005        if wip.shape() != original_shape {
1006            trace!(
1007                "Handling shape {} as innermost {}",
1008                original_shape.blue(),
1009                wip.shape().yellow()
1010            );
1011        }
1012
1013        match outcome.node {
1014            Outcome::Scalar(s) => {
1015                trace!("Parsed scalar value: {}", s.cyan());
1016                wip = self.handle_scalar(wip, s)?;
1017            }
1018            Outcome::ListStarted => {
1019                let shape = wip.innermost_shape();
1020                match shape.def {
1021                    Def::Array(_) => {
1022                        trace!("Array starting for array ({})!", shape.blue());
1023                        // We'll initialize the array elements one by one through the pushback workflow
1024                        // Don't call put_default, as arrays need different initialization
1025                    }
1026                    Def::Slice(_) => {
1027                        trace!("Array starting for slice ({})!", shape.blue());
1028                    }
1029                    Def::List(_) => {
1030                        trace!("Array starting for list ({})!", shape.blue());
1031                        wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
1032                    }
1033                    Def::Scalar(sd) => {
1034                        if matches!(sd.affinity, ScalarAffinity::Empty(_)) {
1035                            trace!("Empty tuple/scalar, nice");
1036                            wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
1037                        } else {
1038                            return Err(self.err(DeserErrorKind::UnsupportedType {
1039                                got: shape,
1040                                wanted: "array, list, tuple, or slice",
1041                            }));
1042                        }
1043                    }
1044                    _ => {
1045                        // For non-collection types, check the Type enum
1046                        if let Type::User(user_ty) = shape.ty {
1047                            match user_ty {
1048                                UserType::Enum(_) => {
1049                                    trace!("Array starting for enum ({})!", shape.blue());
1050                                }
1051                                UserType::Struct(_) => {
1052                                    trace!("Array starting for tuple struct ({})!", shape.blue());
1053                                    wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
1054                                }
1055                                _ => {
1056                                    return Err(self.err(DeserErrorKind::UnsupportedType {
1057                                        got: shape,
1058                                        wanted: "array, list, tuple, or slice",
1059                                    }));
1060                                }
1061                            }
1062                        } else if let Type::Sequence(SequenceType::Tuple(tuple_type)) = shape.ty {
1063                            trace!(
1064                                "Array starting for tuple ({}) with {} fields!",
1065                                shape.blue(),
1066                                tuple_type.fields.len()
1067                            );
1068                            // Initialize the tuple with default values
1069                            wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
1070                            // No special handling needed here - the tuple is already set up correctly
1071                            // and will receive array elements via pushback
1072                        } else {
1073                            return Err(self.err(DeserErrorKind::UnsupportedType {
1074                                got: shape,
1075                                wanted: "array, list, tuple, or slice",
1076                            }));
1077                        }
1078                    }
1079                }
1080                trace!("Beginning pushback");
1081                self.stack.push(Instruction::ListItemOrListClose);
1082                wip = wip.begin_pushback().map_err(|e| self.reflect_err(e))?;
1083            }
1084            Outcome::ListEnded => {
1085                trace!("List closing");
1086                wip = wip.pop().map_err(|e| self.reflect_err(e))?;
1087            }
1088            Outcome::ObjectStarted => {
1089                let shape = wip.shape();
1090                match shape.def {
1091                    Def::Map(_md) => {
1092                        trace!("Object starting for map value ({})!", shape.blue());
1093                        wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
1094                    }
1095                    _ => {
1096                        // For non-collection types, check the Type enum
1097                        if let Type::User(user_ty) = shape.ty {
1098                            match user_ty {
1099                                UserType::Enum(_) => {
1100                                    trace!("Object starting for enum value ({})!", shape.blue());
1101                                    // nothing to do here
1102                                }
1103                                UserType::Struct(_) => {
1104                                    trace!("Object starting for struct value ({})!", shape.blue());
1105                                    // nothing to do here
1106                                }
1107                                _ => {
1108                                    return Err(self.err(DeserErrorKind::UnsupportedType {
1109                                        got: shape,
1110                                        wanted: "map, enum, or struct",
1111                                    }));
1112                                }
1113                            }
1114                        } else if let Type::Sequence(SequenceType::Tuple(tuple_type)) = shape.ty {
1115                            // This could be a tuple that was serialized as an object
1116                            // Despite this being unusual, we'll handle it here for robustness
1117                            trace!(
1118                                "Object starting for tuple ({}) with {} fields - unusual but handling",
1119                                shape.blue(),
1120                                tuple_type.fields.len()
1121                            );
1122                            // Initialize the tuple with default values
1123                            wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
1124                        } else {
1125                            return Err(self.err(DeserErrorKind::UnsupportedType {
1126                                got: shape,
1127                                wanted: "map, enum, struct, or tuple",
1128                            }));
1129                        }
1130                    }
1131                }
1132
1133                self.stack.push(Instruction::ObjectKeyOrObjectClose);
1134            }
1135            Outcome::Resegmented(subspans) => {
1136                trace!("Resegmented with {} subspans (value)", subspans.len());
1137                // Push an instruction to process the current argument again
1138                // (but this time it will use the subspan from the substack)
1139                // self.stack.push(Instruction::ObjectKeyOrObjectClose);
1140                // 1) Go back to expecting another value
1141                // self.stack.push(Instruction::Pop(PopReason::ObjectVal));
1142                // self.stack.push(Instruction::Value(ValueReason::ObjectVal));
1143            }
1144            Outcome::ObjectEnded => todo!(),
1145        }
1146        Ok(wip)
1147    }
1148
1149    fn object_key_or_object_close<'facet>(
1150        &mut self,
1151        mut wip: Wip<'facet, 'shape>,
1152        outcome: Spanned<Outcome<'input>, C>,
1153    ) -> Result<Wip<'facet, 'shape>, DeserError<'input, 'shape, C>>
1154    where
1155        'input: 'facet,
1156    {
1157        trace!(
1158            "STACK: {:?} {}",
1159            self.stack.green(),
1160            "(OK/OC)".bright_yellow()
1161        );
1162        trace!("SUBSTACK: {:?}", self.substack.get().bright_green());
1163        match outcome.node {
1164            Outcome::Scalar(Scalar::String(key)) => {
1165                trace!("Parsed object key: {}", key.cyan());
1166
1167                let mut ignore = false;
1168                let mut needs_pop = true;
1169                let mut handled_by_flatten = false;
1170                let has_substack = !self.substack.get().is_empty();
1171
1172                let shape = wip.innermost_shape();
1173                match shape.ty {
1174                    Type::User(UserType::Struct(sd)) => {
1175                        // First try to find a direct field match
1176                        if let Some(index) = wip.field_index(&key) {
1177                            trace!("It's a struct field");
1178                            wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
1179                        } else {
1180                            trace!(
1181                                "Did not find direct field match in innermost shape {}",
1182                                shape.blue()
1183                            );
1184
1185                            // Check for flattened fields
1186                            let mut found_in_flatten = false;
1187                            for (index, field) in sd.fields.iter().enumerate() {
1188                                if field.flags.contains(FieldFlags::FLATTEN) {
1189                                    trace!("Found flattened field #{}", index);
1190                                    // Enter the flattened field
1191                                    wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
1192
1193                                    // Check if this flattened field has the requested key
1194                                    if let Some(subfield_index) = wip.field_index(&key) {
1195                                        trace!("Found key {} in flattened field", key);
1196                                        wip = wip
1197                                            .field(subfield_index)
1198                                            .map_err(|e| self.reflect_err(e))?;
1199                                        found_in_flatten = true;
1200                                        handled_by_flatten = true;
1201                                        break;
1202                                    } else if let Some((_variant_index, _variant)) =
1203                                        wip.find_variant(&key)
1204                                    {
1205                                        trace!("Found key {} in flattened field", key);
1206                                        wip = wip
1207                                            .variant_named(&key)
1208                                            .map_err(|e| self.reflect_err(e))?;
1209                                        found_in_flatten = true;
1210                                        break;
1211                                    } else {
1212                                        // Key not in this flattened field, go back up
1213                                        wip = wip.pop().map_err(|e| self.reflect_err(e))?;
1214                                    }
1215                                }
1216                            }
1217
1218                            if !found_in_flatten {
1219                                if wip.shape().has_deny_unknown_fields_attr() {
1220                                    trace!(
1221                                        "It's not a struct field AND we're denying unknown fields"
1222                                    );
1223                                    return Err(self.err(DeserErrorKind::UnknownField {
1224                                        field_name: key.to_string(),
1225                                        shape: wip.shape(),
1226                                    }));
1227                                } else {
1228                                    trace!(
1229                                        "It's not a struct field and we're ignoring unknown fields"
1230                                    );
1231                                    ignore = true;
1232                                }
1233                            }
1234                        }
1235                    }
1236                    Type::User(UserType::Enum(_ed)) => match wip.find_variant(&key) {
1237                        Some((index, variant)) => {
1238                            trace!(
1239                                "Selecting variant {}::{}",
1240                                wip.shape().blue(),
1241                                variant.name.yellow(),
1242                            );
1243                            wip = wip.variant(index).map_err(|e| self.reflect_err(e))?;
1244
1245                            // Let's see what's in the variant — if it's tuple-like with only one field, we want to push field 0
1246                            if matches!(variant.data.kind, StructKind::Tuple)
1247                                && variant.data.fields.len() == 1
1248                            {
1249                                trace!(
1250                                    "Tuple variant {}::{} encountered, pushing field 0",
1251                                    wip.shape().blue(),
1252                                    variant.name.yellow()
1253                                );
1254                                wip = wip.field(0).map_err(|e| self.reflect_err(e))?;
1255                                self.stack.push(Instruction::Pop(PopReason::ObjectVal));
1256                            }
1257
1258                            needs_pop = false;
1259                        }
1260                        None => {
1261                            if let Some(_variant_index) = wip.selected_variant() {
1262                                trace!(
1263                                    "Already have a variant selected, treating {} as struct field of {}::{}",
1264                                    key,
1265                                    wip.shape().blue(),
1266                                    wip.selected_variant().unwrap().name.yellow(),
1267                                );
1268                                // Try to find the field index of the key within the selected variant
1269                                if let Some(index) = wip.field_index(&key) {
1270                                    trace!("Found field {} in selected variant", key.blue());
1271                                    wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
1272                                } else if wip.shape().has_deny_unknown_fields_attr() {
1273                                    trace!("Unknown field in variant and denying unknown fields");
1274                                    return Err(self.err(DeserErrorKind::UnknownField {
1275                                        field_name: key.to_string(),
1276                                        shape: wip.shape(),
1277                                    }));
1278                                } else {
1279                                    trace!(
1280                                        "Ignoring unknown field '{}' in variant '{}::{}'",
1281                                        key,
1282                                        wip.shape(),
1283                                        wip.selected_variant().unwrap().name
1284                                    );
1285                                    ignore = true;
1286                                }
1287                            } else {
1288                                return Err(self.err(DeserErrorKind::NoSuchVariant {
1289                                    name: key.to_string(),
1290                                    enum_shape: wip.shape(),
1291                                }));
1292                            }
1293                        }
1294                    },
1295                    _ => {
1296                        // Check if it's a map
1297                        if let Def::Map(_) = shape.def {
1298                            wip = wip.push_map_key().map_err(|e| self.reflect_err(e))?;
1299                            wip = wip.put(key.to_string()).map_err(|e| self.reflect_err(e))?;
1300                            wip = wip.push_map_value().map_err(|e| self.reflect_err(e))?;
1301                        } else {
1302                            return Err(self.err(DeserErrorKind::Unimplemented(
1303                                "object key for non-struct/map",
1304                            )));
1305                        }
1306                    }
1307                }
1308
1309                self.stack.push(Instruction::ObjectKeyOrObjectClose);
1310                if ignore {
1311                    self.stack.push(Instruction::SkipValue);
1312                } else {
1313                    if needs_pop && !handled_by_flatten {
1314                        trace!("Pushing Pop insn to stack (ObjectVal)");
1315                        self.stack.push(Instruction::Pop(PopReason::ObjectVal));
1316                        if has_substack {
1317                            trace!("Pushing SubstackClose insn to stack");
1318                            self.stack.push(Instruction::SubstackClose);
1319                        }
1320                    } else if handled_by_flatten {
1321                        // We need two pops for flattened fields - one for the field itself,
1322                        // one for the containing struct
1323                        trace!("Pushing Pop insn to stack (ObjectVal) for flattened field");
1324                        self.stack.push(Instruction::Pop(PopReason::ObjectVal));
1325                        // Can't tell yet if this is needed, not required for tests (yet),
1326                        // but if we did need it I think it would go in the middle, for the field:
1327                        // if has_substack {
1328                        //     trace!("Pushing SubstackClose insn to stack");
1329                        //     self.stack.push(Instruction::SubstackClose);
1330                        // }
1331                        self.stack.push(Instruction::Pop(PopReason::ObjectVal));
1332                    }
1333                    self.stack.push(Instruction::Value(ValueReason::ObjectVal));
1334                }
1335                Ok(wip)
1336            }
1337            Outcome::ObjectEnded => {
1338                trace!("Object closing");
1339                Ok(wip)
1340            }
1341            Outcome::Resegmented(subspans) => {
1342                trace!(
1343                    "Resegmented into {} subspans ({:?}) - obj. key/close",
1344                    subspans.len(),
1345                    subspans
1346                );
1347                // stay in the same state: parse another 'object key'
1348                self.stack.push(Instruction::ObjectKeyOrObjectClose);
1349                Ok(wip)
1350            }
1351            _ => Err(self.err(DeserErrorKind::UnexpectedOutcome {
1352                got: outcome.node.into_owned(),
1353                wanted: "scalar or object close",
1354            })),
1355        }
1356    }
1357
1358    fn list_item_or_list_close<'facet>(
1359        &mut self,
1360        mut wip: Wip<'facet, 'shape>,
1361        outcome: Spanned<Outcome<'input>, C>,
1362    ) -> Result<Wip<'facet, 'shape>, DeserError<'input, 'shape, C>>
1363    where
1364        'input: 'facet,
1365    {
1366        trace!(
1367            "--- STACK has {:?} {}",
1368            self.stack.green(),
1369            "(LI/LC)".bright_yellow()
1370        );
1371        match outcome.node {
1372            Outcome::ListEnded => {
1373                trace!("List close");
1374                Ok(wip)
1375            }
1376            _ => {
1377                self.stack.push(Instruction::ListItemOrListClose);
1378                self.stack.push(Instruction::Pop(PopReason::ListVal));
1379
1380                trace!(
1381                    "Expecting list item, doing a little push before doing value with outcome {}",
1382                    outcome.magenta()
1383                );
1384                trace!("Before push, wip.shape is {}", wip.shape().blue());
1385
1386                // Special handling for tuples - we need to identify if we're in a tuple context
1387                let is_tuple = matches!(wip.shape().ty, Type::Sequence(SequenceType::Tuple(_)));
1388
1389                if is_tuple {
1390                    trace!("Handling list item for a tuple type");
1391                    // For tuples, we need to use field-based access by index
1392                    wip = wip.push().map_err(|e| self.reflect_err(e))?;
1393                } else {
1394                    // Standard list/array handling
1395                    wip = wip.push().map_err(|e| self.reflect_err(e))?;
1396                }
1397
1398                trace!(" After push, wip.shape is {}", wip.shape().cyan());
1399                wip = self.value(wip, outcome)?;
1400                Ok(wip)
1401            }
1402        }
1403    }
1404}