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};
12
13mod error;
14use alloc::borrow::Cow;
15
16pub use error::*;
17
18mod span;
19use facet_core::{
20    Characteristic, Def, Facet, FieldFlags, ScalarAffinity, SequenceType, StructKind, Type,
21    UserType,
22};
23use owo_colors::OwoColorize;
24pub use span::*;
25
26use facet_reflect::{HeapValue, ReflectError, Wip};
27use log::trace;
28
29#[derive(PartialEq, Debug, Clone)]
30/// A scalar value used during deserialization.
31/// `u64` and `i64` are separated because `i64` doesn't fit in `u64`,
32/// but having `u64` is a fast path for 64-bit architectures — no need to
33/// go through `u128` / `i128` for everything
34pub enum Scalar<'input> {
35    /// Owned or borrowed string data.
36    String(Cow<'input, str>),
37    /// Unsigned 64-bit integer scalar.
38    U64(u64),
39    /// Signed 64-bit integer scalar.
40    I64(i64),
41    /// 64-bit floating-point scalar.
42    F64(f64),
43    /// Boolean scalar.
44    Bool(bool),
45    /// Null scalar (e.g. for formats supporting explicit null).
46    Null,
47}
48
49#[derive(PartialEq, Debug, Clone)]
50/// Expected next input token or structure during deserialization.
51pub enum Expectation {
52    /// Accept a value.
53    Value,
54    /// Expect an object key or the end of an object.
55    ObjectKeyOrObjectClose,
56    /// Expect a value inside an object.
57    ObjectVal,
58    /// Expect a list item or the end of a list.
59    ListItemOrListClose,
60}
61
62#[derive(PartialEq, Debug, Clone)]
63/// Outcome of parsing the next input element.
64pub enum Outcome<'input> {
65    /// Parsed a scalar value.
66    Scalar(Scalar<'input>),
67    /// Starting a list/array.
68    ListStarted,
69    /// Ending a list/array.
70    ListEnded,
71    /// Starting an object/map.
72    ObjectStarted,
73    /// Ending an object/map.
74    ObjectEnded,
75}
76
77impl<'input> From<Scalar<'input>> for Outcome<'input> {
78    fn from(scalar: Scalar<'input>) -> Self {
79        Outcome::Scalar(scalar)
80    }
81}
82
83use core::fmt;
84
85/// Display implementation for `Outcome`, focusing on user-friendly descriptions.
86impl fmt::Display for Outcome<'_> {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        match self {
89            Outcome::Scalar(scalar) => write!(f, "scalar {}", scalar),
90            Outcome::ListStarted => write!(f, "list start"),
91            Outcome::ListEnded => write!(f, "list end"),
92            Outcome::ObjectStarted => write!(f, "object start"),
93            Outcome::ObjectEnded => write!(f, "object end"),
94        }
95    }
96}
97
98/// Display implementation for `Scalar`, for use in displaying `Outcome`.
99impl fmt::Display for Scalar<'_> {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        match self {
102            Scalar::String(s) => write!(f, "string \"{}\"", s),
103            Scalar::U64(val) => write!(f, "u64 {}", val),
104            Scalar::I64(val) => write!(f, "i64 {}", val),
105            Scalar::F64(val) => write!(f, "f64 {}", val),
106            Scalar::Bool(val) => write!(f, "bool {}", val),
107            Scalar::Null => write!(f, "null"),
108        }
109    }
110}
111
112impl Outcome<'_> {
113    fn into_owned(self) -> Outcome<'static> {
114        match self {
115            Outcome::Scalar(scalar) => {
116                let owned_scalar = match scalar {
117                    Scalar::String(cow) => Scalar::String(Cow::Owned(cow.into_owned())),
118                    Scalar::U64(val) => Scalar::U64(val),
119                    Scalar::I64(val) => Scalar::I64(val),
120                    Scalar::F64(val) => Scalar::F64(val),
121                    Scalar::Bool(val) => Scalar::Bool(val),
122                    Scalar::Null => Scalar::Null,
123                };
124                Outcome::Scalar(owned_scalar)
125            }
126            Outcome::ListStarted => Outcome::ListStarted,
127            Outcome::ListEnded => Outcome::ListEnded,
128            Outcome::ObjectStarted => Outcome::ObjectStarted,
129            Outcome::ObjectEnded => Outcome::ObjectEnded,
130        }
131    }
132}
133
134/// Carries the current parsing state and the in-progress value during deserialization.
135/// This bundles the mutable context that must be threaded through parsing steps.
136pub struct NextData<'input: 'facet, 'facet> {
137    /// The offset we're supposed to start parsing from
138    start: usize,
139
140    /// Controls the parsing flow and stack state.
141    runner: StackRunner<'input>,
142
143    /// Holds the intermediate representation of the value being built.
144    pub wip: Wip<'facet>,
145}
146
147impl<'input: 'facet, 'facet> NextData<'input, 'facet> {
148    /// Returns the input (from the start! not from the current position)
149    pub fn input(&self) -> &'input [u8] {
150        self.runner.input
151    }
152
153    /// Returns the parsing start offset.
154    pub fn start(&self) -> usize {
155        self.start
156    }
157}
158
159/// The result of advancing the parser: updated state and parse outcome or error.
160pub type NextResult<'input, 'facet, T, E> = (NextData<'input, 'facet>, Result<T, E>);
161
162/// Trait defining a deserialization format.
163/// Provides the next parsing step based on current state and expected input.
164pub trait Format {
165    /// Advance the parser with current state and expectation, producing the next outcome or error.
166    fn next<'input, 'facet>(
167        &mut self,
168        nd: NextData<'input, 'facet>,
169        expectation: Expectation,
170    ) -> NextResult<'input, 'facet, Spanned<Outcome<'input>>, Spanned<DeserErrorKind>>;
171
172    /// Skip the next value; used to ignore an input.
173    fn skip<'input, 'facet>(
174        &mut self,
175        nd: NextData<'input, 'facet>,
176    ) -> NextResult<'input, 'facet, Span, Spanned<DeserErrorKind>>;
177}
178
179/// Instructions guiding the parsing flow, indicating the next expected action or token.
180#[derive(Debug, Clone, Copy, PartialEq, Eq)]
181pub enum Instruction {
182    /// Expect a value, specifying the context or reason.
183    Value(ValueReason),
184    /// Skip the next value; used to ignore an input.
185    SkipValue,
186    /// Indicate completion of a structure or value; triggers popping from stack.
187    Pop(PopReason),
188    /// Expect an object key or the end of an object.
189    ObjectKeyOrObjectClose,
190    /// Expect a list item or the end of a list.
191    ListItemOrListClose,
192}
193
194/// Reasons for expecting a value, reflecting the current parse context.
195#[derive(Debug, Clone, Copy, PartialEq, Eq)]
196pub enum ValueReason {
197    /// Parsing at the root level.
198    TopLevel,
199    /// Parsing a value inside an object.
200    ObjectVal,
201}
202
203/// Reasons for popping a state from the stack, indicating why a scope is ended.
204#[derive(Debug, Clone, Copy, PartialEq, Eq)]
205pub enum PopReason {
206    /// Ending the top-level parsing scope.
207    TopLevel,
208    /// Ending a value within an object.
209    ObjectVal,
210    /// Ending value within a list
211    ListVal,
212    /// Ending a `Some()` in an option
213    Some,
214}
215
216/// Deserialize a value of type `T` from raw input bytes using format `F`.
217///
218/// This function sets up the initial working state and drives the deserialization process,
219/// ensuring that the resulting value is fully materialized and valid.
220pub fn deserialize<'input, 'facet, T, F>(
221    input: &'input [u8],
222    format: F,
223) -> Result<T, DeserError<'input>>
224where
225    T: Facet<'facet>,
226    F: Format,
227    'input: 'facet,
228{
229    let wip = Wip::alloc_shape(T::SHAPE).map_err(|e| DeserError {
230        input: input.into(),
231        span: Span { start: 0, len: 0 },
232        kind: DeserErrorKind::ReflectError(e),
233    })?;
234    deserialize_wip(wip, input, format)?
235        .materialize()
236        .map_err(|e| DeserError::new_reflect(e, input, Span { start: 0, len: 0 }))
237}
238
239/// Deserializes a working-in-progress value into a fully materialized heap value.
240/// This function drives the parsing loop until the entire input is consumed and the value is complete.
241pub fn deserialize_wip<'input, 'facet, F>(
242    mut wip: Wip<'facet>,
243    input: &'input [u8],
244    mut format: F,
245) -> Result<HeapValue<'facet>, DeserError<'input>>
246where
247    F: Format,
248    'input: 'facet,
249{
250    // This struct is just a bundle of the state that we need to pass around all the time.
251    let mut runner = StackRunner {
252        original_input: input,
253        input,
254        stack: vec![
255            Instruction::Pop(PopReason::TopLevel),
256            Instruction::Value(ValueReason::TopLevel),
257        ],
258        last_span: Span::new(0, 0),
259    };
260
261    macro_rules! next {
262        ($runner:ident, $wip:ident, $expectation:expr, $method:ident) => {{
263            let nd = NextData {
264                start: $runner.last_span.end(), // or supply the appropriate start value if available
265                runner: $runner,
266                wip: $wip,
267            };
268            let (nd, res) = format.next(nd, $expectation);
269            $runner = nd.runner;
270            $wip = nd.wip;
271            let outcome = res.map_err(|span_kind| {
272                $runner.last_span = span_kind.span;
273                $runner.err(span_kind.node)
274            })?;
275            $runner.last_span = outcome.span;
276            $wip = $runner.$method($wip, outcome)?;
277        }};
278    }
279
280    loop {
281        let frame_count = wip.frames_count();
282        debug_assert!(
283            frame_count
284                >= runner
285                    .stack
286                    .iter()
287                    .filter(|f| matches!(f, Instruction::Pop(_)))
288                    .count()
289        );
290
291        let insn = match runner.stack.pop() {
292            Some(insn) => insn,
293            None => unreachable!("Instruction stack is empty"),
294        };
295
296        trace!("[{frame_count}] Instruction {:?}", insn.yellow());
297
298        match insn {
299            Instruction::Pop(reason) => {
300                wip = runner.pop(wip, reason)?;
301
302                if reason == PopReason::TopLevel {
303                    return wip.build().map_err(|e| runner.reflect_err(e));
304                } else {
305                    wip = wip.pop().map_err(|e| runner.reflect_err(e))?;
306                }
307            }
308            Instruction::Value(_why) => {
309                let expectation = match _why {
310                    ValueReason::TopLevel => Expectation::Value,
311                    ValueReason::ObjectVal => Expectation::ObjectVal,
312                };
313                next!(runner, wip, expectation, value);
314            }
315            Instruction::ObjectKeyOrObjectClose => {
316                next!(
317                    runner,
318                    wip,
319                    Expectation::ObjectKeyOrObjectClose,
320                    object_key_or_object_close
321                );
322            }
323            Instruction::ListItemOrListClose => {
324                next!(
325                    runner,
326                    wip,
327                    Expectation::ListItemOrListClose,
328                    list_item_or_list_close
329                );
330            }
331            Instruction::SkipValue => {
332                // Call F::skip to skip over the next value in the input
333                let nd = NextData {
334                    start: runner.last_span.end(),
335                    runner,
336                    wip,
337                };
338                let (nd, res) = format.skip(nd);
339                runner = nd.runner;
340                wip = nd.wip;
341                // Only propagate error, don't modify wip, since skip just advances input
342                let span = res.map_err(|span_kind| {
343                    runner.last_span = span_kind.span;
344                    runner.err(span_kind.node)
345                })?;
346                // do the actual skip
347                runner.last_span = span;
348            }
349        }
350    }
351}
352
353#[doc(hidden)]
354/// Maintains the parsing state and context necessary to drive deserialization.
355///
356/// This struct tracks what the parser expects next, manages input position,
357/// and remembers the span of the last processed token to provide accurate error reporting.
358pub struct StackRunner<'input> {
359    /// A version of the input that doesn't advance as we parse.
360    pub original_input: &'input [u8],
361    /// The raw input data being deserialized.
362    pub input: &'input [u8],
363
364    /// Stack of parsing instructions guiding the control flow.
365    pub stack: Vec<Instruction>,
366    /// Span of the last processed token, for accurate error reporting.
367    pub last_span: Span,
368}
369
370impl<'input> StackRunner<'input> {
371    /// Convenience function to create a DeserError using the original input and last_span.
372    fn err(&self, kind: DeserErrorKind) -> DeserError<'input> {
373        DeserError::new(kind, self.original_input, self.last_span)
374    }
375
376    /// Convenience function to create a DeserError from a ReflectError,
377    /// using the original input and last_span for context.
378    fn reflect_err(&self, err: ReflectError) -> DeserError<'input> {
379        DeserError::new_reflect(err, self.original_input, self.last_span)
380    }
381
382    pub fn pop<'facet>(
383        &mut self,
384        mut wip: Wip<'facet>,
385        reason: PopReason,
386    ) -> Result<Wip<'facet>, DeserError<'input>> {
387        trace!("Popping because {:?}", reason.yellow());
388
389        let container_shape = wip.shape();
390        match container_shape.ty {
391            Type::User(UserType::Struct(sd)) => {
392                let mut has_unset = false;
393
394                trace!("Let's check all fields are initialized");
395                for (index, field) in sd.fields.iter().enumerate() {
396                    let is_set = wip.is_field_set(index).map_err(|err| {
397                        trace!("Error checking field set status: {:?}", err);
398                        self.reflect_err(err)
399                    })?;
400                    if !is_set {
401                        if field.flags.contains(FieldFlags::DEFAULT) {
402                            wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
403                            if let Some(default_in_place_fn) = field.vtable.default_fn {
404                                wip = wip
405                                    .put_from_fn(default_in_place_fn)
406                                    .map_err(|e| self.reflect_err(e))?;
407                                trace!(
408                                    "Field #{} {} @ {} was set to default value (via custom fn)",
409                                    index.yellow(),
410                                    field.name.green(),
411                                    field.offset.blue(),
412                                );
413                            } else {
414                                if !field.shape().is(Characteristic::Default) {
415                                    return Err(self.reflect_err(
416                                        ReflectError::DefaultAttrButNoDefaultImpl {
417                                            shape: field.shape(),
418                                        },
419                                    ));
420                                }
421                                wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
422                                trace!(
423                                    "Field #{} {} @ {} was set to default value (via default impl)",
424                                    index.yellow(),
425                                    field.name.green(),
426                                    field.offset.blue(),
427                                );
428                            }
429                            wip = wip.pop().map_err(|e| self.reflect_err(e))?;
430                        } else {
431                            trace!(
432                                "Field #{} {} @ {} is not initialized",
433                                index.yellow(),
434                                field.name.green(),
435                                field.offset.blue(),
436                            );
437                            has_unset = true;
438                        }
439                    }
440                }
441
442                if has_unset && container_shape.has_default_attr() {
443                    // let's allocate and build a default value
444                    let default_val = Wip::alloc_shape(container_shape)
445                        .map_err(|e| self.reflect_err(e))?
446                        .put_default()
447                        .map_err(|e| self.reflect_err(e))?
448                        .build()
449                        .map_err(|e| self.reflect_err(e))?;
450                    let peek = default_val.peek().into_struct().unwrap();
451
452                    for (index, field) in sd.fields.iter().enumerate() {
453                        let is_set = wip.is_field_set(index).map_err(|err| {
454                            trace!("Error checking field set status: {:?}", err);
455                            self.reflect_err(err)
456                        })?;
457                        if !is_set {
458                            let address_of_field_from_default = peek.field(index).unwrap().data();
459                            wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
460                            wip = wip
461                                .put_shape(address_of_field_from_default, field.shape())
462                                .map_err(|e| self.reflect_err(e))?;
463                            wip = wip.pop().map_err(|e| self.reflect_err(e))?;
464                        }
465                    }
466                }
467            }
468            Type::User(UserType::Enum(ed)) => {
469                trace!("Checking if enum is initialized correctly");
470
471                // Check if a variant has been selected
472                if let Some(variant) = wip.selected_variant() {
473                    trace!("Variant {} is selected", variant.name.blue());
474
475                    // Check if all fields in the variant are initialized
476                    if !variant.data.fields.is_empty() {
477                        let mut has_unset = false;
478
479                        for (index, field) in variant.data.fields.iter().enumerate() {
480                            let is_set = wip.is_field_set(index).map_err(|err| {
481                                trace!("Error checking field set status: {:?}", err);
482                                self.reflect_err(err)
483                            })?;
484
485                            if !is_set {
486                                if field.flags.contains(FieldFlags::DEFAULT) {
487                                    wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
488                                    if let Some(default_in_place_fn) = field.vtable.default_fn {
489                                        wip = wip
490                                            .put_from_fn(default_in_place_fn)
491                                            .map_err(|e| self.reflect_err(e))?;
492                                        trace!(
493                                            "Field #{} @ {} in variant {} was set to default value (via custom fn)",
494                                            index.yellow(),
495                                            field.offset.blue(),
496                                            variant.name
497                                        );
498                                    } else {
499                                        if !field.shape().is(Characteristic::Default) {
500                                            return Err(self.reflect_err(
501                                                ReflectError::DefaultAttrButNoDefaultImpl {
502                                                    shape: field.shape(),
503                                                },
504                                            ));
505                                        }
506                                        wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
507                                        trace!(
508                                            "Field #{} @ {} in variant {} was set to default value (via default impl)",
509                                            index.yellow(),
510                                            field.offset.blue(),
511                                            variant.name
512                                        );
513                                    }
514                                    wip = wip.pop().map_err(|e| self.reflect_err(e))?;
515                                } else {
516                                    trace!(
517                                        "Field #{} @ {} in variant {} is not initialized",
518                                        index.yellow(),
519                                        field.offset.blue(),
520                                        variant.name
521                                    );
522                                    has_unset = true;
523                                }
524                            }
525                        }
526
527                        if has_unset && container_shape.has_default_attr() {
528                            trace!("Enum has DEFAULT attr but variant has uninitialized fields");
529                            // Handle similar to struct, allocate and build default value for variant
530                            let default_val = Wip::alloc_shape(container_shape)
531                                .map_err(|e| self.reflect_err(e))?
532                                .put_default()
533                                .map_err(|e| self.reflect_err(e))?
534                                .build()
535                                .map_err(|e| self.reflect_err(e))?;
536
537                            let peek = default_val.peek();
538                            let peek_enum = peek.into_enum().map_err(|e| self.reflect_err(e))?;
539                            let default_variant = peek_enum
540                                .active_variant()
541                                .map_err(|e| self.err(DeserErrorKind::VariantError(e)))?;
542
543                            if default_variant == &variant {
544                                // It's the same variant, fill in the missing fields
545                                for (index, field) in variant.data.fields.iter().enumerate() {
546                                    let is_set = wip.is_field_set(index).map_err(|err| {
547                                        trace!("Error checking field set status: {:?}", err);
548                                        self.reflect_err(err)
549                                    })?;
550                                    if !is_set {
551                                        if let Ok(Some(def_field)) = peek_enum.field(index) {
552                                            wip = wip
553                                                .field(index)
554                                                .map_err(|e| self.reflect_err(e))?;
555                                            wip = wip
556                                                .put_shape(def_field.data(), field.shape())
557                                                .map_err(|e| self.reflect_err(e))?;
558                                            wip = wip.pop().map_err(|e| self.reflect_err(e))?;
559                                        }
560                                    }
561                                }
562                            }
563                        }
564                    }
565                } else if container_shape.has_default_attr() {
566                    // No variant selected, but enum has default attribute - set to default
567                    trace!("No variant selected but enum has DEFAULT attr; setting to default");
568                    let default_val = Wip::alloc_shape(container_shape)
569                        .map_err(|e| self.reflect_err(e))?
570                        .put_default()
571                        .map_err(|e| self.reflect_err(e))?
572                        .build()
573                        .map_err(|e| self.reflect_err(e))?;
574
575                    let peek = default_val.peek();
576                    let peek_enum = peek.into_enum().map_err(|e| self.reflect_err(e))?;
577                    let default_variant_idx = peek_enum
578                        .variant_index()
579                        .map_err(|e| self.err(DeserErrorKind::VariantError(e)))?;
580
581                    // Select the default variant
582                    wip = wip
583                        .variant(default_variant_idx)
584                        .map_err(|e| self.reflect_err(e))?;
585
586                    // Copy all fields from default value
587                    let variant = &ed.variants[default_variant_idx];
588                    for (index, field) in variant.data.fields.iter().enumerate() {
589                        if let Ok(Some(def_field)) = peek_enum.field(index) {
590                            wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
591                            wip = wip
592                                .put_shape(def_field.data(), field.shape())
593                                .map_err(|e| self.reflect_err(e))?;
594                            wip = wip.pop().map_err(|e| self.reflect_err(e))?;
595                        }
596                    }
597                }
598            }
599            _ => {
600                trace!(
601                    "Thing being popped is not a container I guess (it's a {})",
602                    wip.shape()
603                );
604            }
605        }
606        Ok(wip)
607    }
608
609    /// Internal common handler for GotScalar outcome, to deduplicate code.
610    fn handle_scalar<'facet>(
611        &self,
612        wip: Wip<'facet>,
613        scalar: Scalar<'input>,
614    ) -> Result<Wip<'facet>, DeserError<'input>> {
615        match scalar {
616            Scalar::String(cow) => {
617                match wip.innermost_shape().ty {
618                    Type::User(UserType::Enum(_)) => {
619                        if wip.selected_variant().is_some() {
620                            // If we already have a variant selected, just put the string
621                            wip.put(cow.to_string()).map_err(|e| self.reflect_err(e))
622                        } else {
623                            // Try to select the variant
624                            match wip.find_variant(&cow) {
625                                Some((variant_index, _)) => {
626                                    wip.variant(variant_index).map_err(|e| self.reflect_err(e))
627                                }
628                                None => Err(self.err(DeserErrorKind::NoSuchVariant {
629                                    name: cow.to_string(),
630                                    enum_shape: wip.innermost_shape(),
631                                })),
632                            }
633                        }
634                    }
635                    _ => wip.put(cow.to_string()).map_err(|e| self.reflect_err(e)),
636                }
637            }
638            Scalar::U64(value) => wip.put(value).map_err(|e| self.reflect_err(e)),
639            Scalar::I64(value) => wip.put(value).map_err(|e| self.reflect_err(e)),
640            Scalar::F64(value) => wip.put(value).map_err(|e| self.reflect_err(e)),
641            Scalar::Bool(value) => wip.put(value).map_err(|e| self.reflect_err(e)),
642            Scalar::Null => wip.put_default().map_err(|e| self.reflect_err(e)),
643        }
644    }
645
646    /// Handle value parsing
647    fn value<'facet>(
648        &mut self,
649        mut wip: Wip<'facet>,
650        outcome: Spanned<Outcome<'input>>,
651    ) -> Result<Wip<'facet>, DeserError<'input>> {
652        trace!(
653            "Handling value at {} (innermost {})",
654            wip.shape().blue(),
655            wip.innermost_shape().yellow()
656        );
657
658        match outcome.node {
659            Outcome::Scalar(Scalar::Null) => {
660                return wip.put_default().map_err(|e| self.reflect_err(e));
661            }
662            _ => {
663                if matches!(wip.shape().def, Def::Option(_)) {
664                    // TODO: Update option handling
665                    trace!("Starting Some(_) option for {}", wip.shape().blue());
666                    wip = wip.push_some().map_err(|e| self.reflect_err(e))?;
667                    self.stack.push(Instruction::Pop(PopReason::Some));
668                }
669            }
670        }
671
672        match outcome.node {
673            Outcome::Scalar(s) => {
674                wip = self.handle_scalar(wip, s)?;
675            }
676            Outcome::ListStarted => {
677                let shape = wip.innermost_shape();
678                match shape.def {
679                    Def::Array(_) => {
680                        trace!("Array starting for array ({})!", shape.blue());
681                        // We'll initialize the array elements one by one through the pushback workflow
682                        // Don't call put_default, as arrays need different initialization
683                    }
684                    Def::Slice(_) => {
685                        trace!("Array starting for slice ({})!", shape.blue());
686                    }
687                    Def::List(_) => {
688                        trace!("Array starting for list ({})!", shape.blue());
689                        wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
690                    }
691                    Def::Scalar(sd) => {
692                        if matches!(sd.affinity, ScalarAffinity::Empty(_)) {
693                            trace!("Empty tuple/scalar, nice");
694                            wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
695                        } else {
696                            return Err(self.err(DeserErrorKind::UnsupportedType {
697                                got: shape,
698                                wanted: "array, list, tuple, or slice",
699                            }));
700                        }
701                    }
702                    _ => {
703                        // For non-collection types, check the Type enum
704                        if let Type::User(user_ty) = shape.ty {
705                            match user_ty {
706                                UserType::Enum(_) => {
707                                    trace!("Array starting for enum ({})!", shape.blue());
708                                }
709                                UserType::Struct(_) => {
710                                    trace!("Array starting for tuple struct ({})!", shape.blue());
711                                    wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
712                                }
713                                _ => {
714                                    return Err(self.err(DeserErrorKind::UnsupportedType {
715                                        got: shape,
716                                        wanted: "array, list, tuple, or slice",
717                                    }));
718                                }
719                            }
720                        } else if let Type::Sequence(SequenceType::Tuple(tuple_type)) = shape.ty {
721                            trace!(
722                                "Array starting for tuple ({}) with {} fields!",
723                                shape.blue(),
724                                tuple_type.fields.len()
725                            );
726                            // Initialize the tuple with default values
727                            wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
728                            // No special handling needed here - the tuple is already set up correctly
729                            // and will receive array elements via pushback
730                        } else {
731                            return Err(self.err(DeserErrorKind::UnsupportedType {
732                                got: shape,
733                                wanted: "array, list, tuple, or slice",
734                            }));
735                        }
736                    }
737                }
738                trace!("Beginning pushback");
739                self.stack.push(Instruction::ListItemOrListClose);
740                wip = wip.begin_pushback().map_err(|e| self.reflect_err(e))?;
741            }
742            Outcome::ListEnded => {
743                trace!("List closing");
744                wip = wip.pop().map_err(|e| self.reflect_err(e))?;
745            }
746            Outcome::ObjectStarted => {
747                let shape = wip.innermost_shape();
748                match shape.def {
749                    Def::Map(_md) => {
750                        trace!("Object starting for map value ({})!", shape.blue());
751                        wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
752                    }
753                    _ => {
754                        // For non-collection types, check the Type enum
755                        if let Type::User(user_ty) = shape.ty {
756                            match user_ty {
757                                UserType::Enum(_) => {
758                                    trace!("Object starting for enum value ({})!", shape.blue());
759                                    // nothing to do here
760                                }
761                                UserType::Struct(_) => {
762                                    trace!("Object starting for struct value ({})!", shape.blue());
763                                    // nothing to do here
764                                }
765                                _ => {
766                                    return Err(self.err(DeserErrorKind::UnsupportedType {
767                                        got: shape,
768                                        wanted: "map, enum, or struct",
769                                    }));
770                                }
771                            }
772                        } else if let Type::Sequence(SequenceType::Tuple(tuple_type)) = shape.ty {
773                            // This could be a tuple that was serialized as an object
774                            // Despite this being unusual, we'll handle it here for robustness
775                            trace!(
776                                "Object starting for tuple ({}) with {} fields - unusual but handling",
777                                shape.blue(),
778                                tuple_type.fields.len()
779                            );
780                            // Initialize the tuple with default values
781                            wip = wip.put_default().map_err(|e| self.reflect_err(e))?;
782                        } else {
783                            return Err(self.err(DeserErrorKind::UnsupportedType {
784                                got: shape,
785                                wanted: "map, enum, struct, or tuple",
786                            }));
787                        }
788                    }
789                }
790
791                self.stack.push(Instruction::ObjectKeyOrObjectClose);
792            }
793            Outcome::ObjectEnded => todo!(),
794        }
795        Ok(wip)
796    }
797
798    fn object_key_or_object_close<'facet>(
799        &mut self,
800        mut wip: Wip<'facet>,
801        outcome: Spanned<Outcome<'input>>,
802    ) -> Result<Wip<'facet>, DeserError<'input>>
803    where
804        'input: 'facet,
805    {
806        match outcome.node {
807            Outcome::Scalar(Scalar::String(key)) => {
808                trace!("Parsed object key: {}", key.cyan());
809
810                let mut ignore = false;
811                let mut needs_pop = true;
812                let mut handled_by_flatten = false;
813
814                let shape = wip.innermost_shape();
815                match shape.ty {
816                    Type::User(UserType::Struct(sd)) => {
817                        // First try to find a direct field match
818                        if let Some(index) = wip.field_index(&key) {
819                            trace!("It's a struct field");
820                            wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
821                        } else {
822                            // Check for flattened fields
823                            let mut found_in_flatten = false;
824                            for (index, field) in sd.fields.iter().enumerate() {
825                                if field.flags.contains(FieldFlags::FLATTEN) {
826                                    trace!("Found flattened field #{}", index);
827                                    // Enter the flattened field
828                                    wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
829
830                                    // Check if this flattened field has the requested key
831                                    if let Some(subfield_index) = wip.field_index(&key) {
832                                        trace!("Found key {} in flattened field", key);
833                                        wip = wip
834                                            .field(subfield_index)
835                                            .map_err(|e| self.reflect_err(e))?;
836                                        found_in_flatten = true;
837                                        handled_by_flatten = true;
838                                        break;
839                                    } else if let Some((_variant_index, _variant)) =
840                                        wip.find_variant(&key)
841                                    {
842                                        trace!("Found key {} in flattened field", key);
843                                        wip = wip
844                                            .variant_named(&key)
845                                            .map_err(|e| self.reflect_err(e))?;
846                                        found_in_flatten = true;
847                                        break;
848                                    } else {
849                                        // Key not in this flattened field, go back up
850                                        wip = wip.pop().map_err(|e| self.reflect_err(e))?;
851                                    }
852                                }
853                            }
854
855                            if !found_in_flatten {
856                                if wip.shape().has_deny_unknown_fields_attr() {
857                                    trace!(
858                                        "It's not a struct field AND we're denying unknown fields"
859                                    );
860                                    return Err(self.err(DeserErrorKind::UnknownField {
861                                        field_name: key.to_string(),
862                                        shape: wip.shape(),
863                                    }));
864                                } else {
865                                    trace!(
866                                        "It's not a struct field and we're ignoring unknown fields"
867                                    );
868                                    ignore = true;
869                                }
870                            }
871                        }
872                    }
873                    Type::User(UserType::Enum(_ed)) => match wip.find_variant(&key) {
874                        Some((index, variant)) => {
875                            trace!(
876                                "Selecting variant {}::{}",
877                                wip.shape().blue(),
878                                variant.name.yellow(),
879                            );
880                            wip = wip.variant(index).map_err(|e| self.reflect_err(e))?;
881
882                            // Let's see what's in the variant — if it's tuple-like with only one field, we want to push field 0
883                            if matches!(variant.data.kind, StructKind::Tuple)
884                                && variant.data.fields.len() == 1
885                            {
886                                trace!(
887                                    "Tuple variant {}::{} encountered, pushing field 0",
888                                    wip.shape().blue(),
889                                    variant.name.yellow()
890                                );
891                                wip = wip.field(0).map_err(|e| self.reflect_err(e))?;
892                                self.stack.push(Instruction::Pop(PopReason::ObjectVal));
893                            }
894
895                            needs_pop = false;
896                        }
897                        None => {
898                            if let Some(_variant_index) = wip.selected_variant() {
899                                trace!(
900                                    "Already have a variant selected, treating {} as struct field of {}::{}",
901                                    key,
902                                    wip.shape().blue(),
903                                    wip.selected_variant().unwrap().name.yellow(),
904                                );
905                                // Try to find the field index of the key within the selected variant
906                                if let Some(index) = wip.field_index(&key) {
907                                    trace!("Found field {} in selected variant", key.blue());
908                                    wip = wip.field(index).map_err(|e| self.reflect_err(e))?;
909                                } else if wip.shape().has_deny_unknown_fields_attr() {
910                                    trace!("Unknown field in variant and denying unknown fields");
911                                    return Err(self.err(DeserErrorKind::UnknownField {
912                                        field_name: key.to_string(),
913                                        shape: wip.shape(),
914                                    }));
915                                } else {
916                                    trace!(
917                                        "Ignoring unknown field '{}' in variant '{}::{}'",
918                                        key,
919                                        wip.shape(),
920                                        wip.selected_variant().unwrap().name
921                                    );
922                                    ignore = true;
923                                }
924                            } else {
925                                return Err(self.err(DeserErrorKind::NoSuchVariant {
926                                    name: key.to_string(),
927                                    enum_shape: wip.shape(),
928                                }));
929                            }
930                        }
931                    },
932                    _ => {
933                        // Check if it's a map
934                        if let Def::Map(_) = shape.def {
935                            wip = wip.push_map_key().map_err(|e| self.reflect_err(e))?;
936                            wip = wip.put(key.to_string()).map_err(|e| self.reflect_err(e))?;
937                            wip = wip.push_map_value().map_err(|e| self.reflect_err(e))?;
938                        } else {
939                            return Err(self.err(DeserErrorKind::Unimplemented(
940                                "object key for non-struct/map",
941                            )));
942                        }
943                    }
944                }
945
946                self.stack.push(Instruction::ObjectKeyOrObjectClose);
947                if ignore {
948                    self.stack.push(Instruction::SkipValue);
949                } else {
950                    if needs_pop && !handled_by_flatten {
951                        trace!("Pushing Pop insn to stack (ObjectVal)");
952                        self.stack.push(Instruction::Pop(PopReason::ObjectVal));
953                    } else if handled_by_flatten {
954                        // We need two pops for flattened fields - one for the field itself,
955                        // one for the containing struct
956                        trace!("Pushing Pop insn to stack (ObjectVal) for flattened field");
957                        self.stack.push(Instruction::Pop(PopReason::ObjectVal));
958                        self.stack.push(Instruction::Pop(PopReason::ObjectVal));
959                    }
960                    self.stack.push(Instruction::Value(ValueReason::ObjectVal));
961                }
962                Ok(wip)
963            }
964            Outcome::ObjectEnded => {
965                trace!("Object closing");
966                Ok(wip)
967            }
968            _ => Err(self.err(DeserErrorKind::UnexpectedOutcome {
969                got: outcome.node.into_owned(),
970                wanted: "scalar or object close",
971            })),
972        }
973    }
974
975    fn list_item_or_list_close<'facet>(
976        &mut self,
977        mut wip: Wip<'facet>,
978        outcome: Spanned<Outcome<'input>>,
979    ) -> Result<Wip<'facet>, DeserError<'input>>
980    where
981        'input: 'facet,
982    {
983        match outcome.node {
984            Outcome::ListEnded => {
985                trace!("List close");
986                Ok(wip)
987            }
988            _ => {
989                self.stack.push(Instruction::ListItemOrListClose);
990                self.stack.push(Instruction::Pop(PopReason::ListVal));
991
992                trace!(
993                    "Expecting list item, doing a little push before doing value with outcome {}",
994                    outcome.magenta()
995                );
996                trace!("Before push, wip.shape is {}", wip.shape().blue());
997
998                // Special handling for tuples - we need to identify if we're in a tuple context
999                let is_tuple = matches!(
1000                    wip.innermost_shape().ty,
1001                    Type::Sequence(SequenceType::Tuple(_))
1002                );
1003
1004                if is_tuple {
1005                    trace!("Handling list item for a tuple type");
1006                    // For tuples, we need to use field-based access by index
1007                    wip = wip.push().map_err(|e| self.reflect_err(e))?;
1008                } else {
1009                    // Standard list/array handling
1010                    wip = wip.push().map_err(|e| self.reflect_err(e))?;
1011                }
1012
1013                trace!(" After push, wip.shape is {}", wip.shape().cyan());
1014                wip = self.value(wip, outcome)?;
1015                Ok(wip)
1016            }
1017        }
1018    }
1019}