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