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