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