facet_json/
deserialize.rs

1use alloc::string::{String, ToString};
2use alloc::{vec, vec::Vec};
3use facet_core::{Characteristic, Def, Facet, ScalarAffinity, StructKind};
4use facet_reflect::{HeapValue, ReflectError, Wip};
5use log::trace;
6use owo_colors::OwoColorize;
7
8mod tokenizer;
9pub use tokenizer::*;
10
11mod error;
12pub use error::*;
13
14/// Deserializes a JSON string into a value of type `T` that implements `Facet`.
15///
16/// This function takes a JSON string representation and converts it into a Rust
17/// value of the specified type `T`. The type must implement the `Facet` trait
18/// to provide the necessary type information for deserialization.
19pub fn from_str<'input, 'facet, T>(json: &'input str) -> Result<T, JsonError<'input>>
20where
21    T: Facet<'facet>,
22    'input: 'facet,
23{
24    from_slice(json.as_bytes())
25}
26
27/// Deserialize JSON from a slice
28///
29/// # Arguments
30///
31/// * `json` - A slice of bytes representing the JSON input.
32///
33/// # Returns
34///
35/// A result containing the deserialized value of type `T` or a `JsonParseErrorWithContext`.
36pub fn from_slice<'input, 'facet, T>(json: &'input [u8]) -> Result<T, JsonError<'input>>
37where
38    T: Facet<'facet>,
39    'input: 'facet,
40{
41    let wip = Wip::alloc::<T>()
42        .map_err(|e| JsonError::new_reflect(e, json, Span::new(0, json.len()), "$".to_string()))?;
43    let heap_value = from_slice_wip(wip, json)?;
44    Ok(heap_value.materialize::<T>().unwrap())
45}
46
47/// Represents the next expected token or structure while parsing.
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49enum Instruction {
50    Value,
51    SkipValue,
52    Pop(PopReason),
53    ObjectKeyOrObjectClose,
54    CommaThenObjectKeyOrObjectClose,
55    ArrayItemOrArrayClose,
56    CommaThenArrayItemOrArrayClose,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60enum PopReason {
61    TopLevel,
62    ObjectVal,
63    ArrayItem,
64    Some,
65}
66
67/// Deserialize a JSON string into a Wip object.
68///
69/// # Arguments
70///
71/// * `wip` - A mutable Wip object to deserialize into.
72/// * `input` - A byte slice representing the JSON input.
73///
74/// # Returns
75///
76/// A result containing the updated `Wip` or a `JsonParseErrorWithContext`.
77pub fn from_slice_wip<'input: 'facet, 'facet>(
78    mut wip: Wip<'facet>,
79    input: &'input [u8],
80) -> Result<HeapValue<'facet>, JsonError<'input>> {
81    // This struct is just a bundle of the state that we need to pass around all the time.
82    let mut runner = StackRunner {
83        stack: vec![Instruction::Pop(PopReason::TopLevel), Instruction::Value],
84        tokenizer: Tokenizer::new(input),
85        last_span: Span::new(0, 0),
86        unread_token: None,
87        input,
88    };
89
90    loop {
91        let frame_count = wip.frames_count();
92        debug_assert!(
93            frame_count
94                >= runner
95                    .stack
96                    .iter()
97                    .filter(|f| matches!(f, Instruction::Pop(_)))
98                    .count()
99        );
100
101        let insn = match runner.stack.pop() {
102            Some(insn) => insn,
103            None => unreachable!("Instruction stack is empty"),
104        };
105
106        trace!("[{frame_count}] Instruction {:?}", insn.yellow());
107
108        match insn {
109            Instruction::Pop(reason) => {
110                wip = runner.pop(wip, reason)?;
111
112                if reason == PopReason::TopLevel {
113                    let path = wip.path();
114                    return wip
115                        .build()
116                        .map_err(|e| JsonError::new_reflect(e, input, runner.last_span, path));
117                } else {
118                    let path = wip.path();
119                    wip = wip
120                        .pop()
121                        .map_err(|e| JsonError::new_reflect(e, input, runner.last_span, path))?;
122                }
123            }
124            Instruction::SkipValue => runner.skip_value(&wip)?,
125            Instruction::Value => wip = runner.value(wip)?,
126            Instruction::ObjectKeyOrObjectClose => wip = runner.object_key_or_object_close(wip)?,
127            Instruction::CommaThenObjectKeyOrObjectClose => {
128                runner.comma_then_object_key_or_object_close(&wip)?
129            }
130            Instruction::ArrayItemOrArrayClose => wip = runner.array_item_or_array_close(wip)?,
131            Instruction::CommaThenArrayItemOrArrayClose => {
132                wip = runner.comma_then_array_item_or_array_close(wip)?
133            }
134        }
135    }
136}
137
138/// It runs along the stack!
139struct StackRunner<'a> {
140    /// Look! A stack!
141    stack: Vec<Instruction>,
142    tokenizer: Tokenizer<'a>,
143    last_span: Span,
144    unread_token: Option<Spanned<Token>>,
145    input: &'a [u8],
146}
147
148impl<'a> StackRunner<'a> {
149    fn pop<'f>(&mut self, mut wip: Wip<'f>, reason: PopReason) -> Result<Wip<'f>, JsonError<'a>> {
150        trace!("Popping because {:?}", reason.yellow());
151
152        let container_shape = wip.shape();
153        match container_shape.def {
154            Def::Struct(sd) => {
155                let mut has_unset = false;
156
157                trace!("Let's check all fields are initialized");
158                for (index, field) in sd.fields.iter().enumerate() {
159                    let is_set = wip.is_field_set(index).map_err(|err| {
160                        trace!("Error checking field set status: {:?}", err);
161                        JsonError::new_reflect(err, self.input, self.last_span, wip.path())
162                    })?;
163                    if !is_set {
164                        if let Some(default_in_place_fn) = field.maybe_default_fn() {
165                            let path = wip.path();
166                            wip = wip.field(index).map_err(|e| {
167                                JsonError::new_reflect(e, self.input, self.last_span, path)
168                            })?;
169                            if let Some(default_in_place_fn) = default_in_place_fn {
170                                let path = wip.path();
171                                wip = wip.put_from_fn(default_in_place_fn).map_err(|e| {
172                                    JsonError::new_reflect(e, self.input, self.last_span, path)
173                                })?;
174                                trace!(
175                                    "Field #{} {:?} was set to default value (via custom fn)",
176                                    index.yellow(),
177                                    field.blue()
178                                );
179                            } else {
180                                if !field.shape().is(Characteristic::Default) {
181                                    return Err(JsonError::new_reflect(
182                                        ReflectError::DefaultAttrButNoDefaultImpl {
183                                            shape: field.shape(),
184                                        },
185                                        self.input,
186                                        self.last_span,
187                                        wip.path(),
188                                    ));
189                                }
190                                let path = wip.path();
191                                wip = wip.put_default().map_err(|e| {
192                                    JsonError::new_reflect(e, self.input, self.last_span, path)
193                                })?;
194                                trace!(
195                                    "Field #{} {:?} was set to default value (via default impl)",
196                                    index.yellow(),
197                                    field.blue()
198                                );
199                            }
200                            let path = wip.path();
201                            wip = wip.pop().map_err(|e| {
202                                JsonError::new_reflect(e, self.input, self.last_span, path)
203                            })?;
204                        } else {
205                            trace!(
206                                "Field #{} {:?} is not initialized",
207                                index.yellow(),
208                                field.blue()
209                            );
210                            has_unset = true;
211                        }
212                    }
213                }
214
215                if has_unset && container_shape.has_default_attr() {
216                    // let's allocate and build a default value
217                    let default_val = Wip::alloc_shape(container_shape)
218                        .map_err(|e| {
219                            JsonError::new_reflect(e, self.input, self.last_span, wip.path())
220                        })?
221                        .put_default()
222                        .map_err(|e| {
223                            JsonError::new_reflect(e, self.input, self.last_span, wip.path())
224                        })?
225                        .build()
226                        .map_err(|e| {
227                            JsonError::new_reflect(e, self.input, self.last_span, wip.path())
228                        })?;
229                    let peek = default_val.peek().into_struct().unwrap();
230
231                    for (index, field) in sd.fields.iter().enumerate() {
232                        let is_set = wip.is_field_set(index).map_err(|err| {
233                            trace!("Error checking field set status: {:?}", err);
234                            JsonError::new_reflect(err, self.input, self.last_span, wip.path())
235                        })?;
236                        if !is_set {
237                            let address_of_field_from_default = peek.field(index).unwrap().data();
238                            let path = wip.path();
239                            wip = wip.field(index).map_err(|e| {
240                                JsonError::new_reflect(e, self.input, self.last_span, path)
241                            })?;
242                            let path = wip.path();
243                            wip = wip
244                                .put_shape(address_of_field_from_default, field.shape())
245                                .map_err(|e| {
246                                    JsonError::new_reflect(e, self.input, self.last_span, path)
247                                })?;
248                            let path = wip.path();
249                            wip = wip.pop().map_err(|e| {
250                                JsonError::new_reflect(e, self.input, self.last_span, path)
251                            })?;
252                        }
253                    }
254                }
255            }
256            Def::Enum(_) => {
257                trace!(
258                    "TODO: make sure enums are initialized (support container-level and field-level default, etc.)"
259                );
260            }
261            _ => {
262                trace!("Thing being popped is not a container I guess");
263            }
264        }
265        Ok(wip)
266    }
267
268    fn skip_value(&mut self, wip: &Wip<'_>) -> Result<(), JsonError<'a>> {
269        let token = self.read_token(wip)?;
270        match token.node {
271            Token::LBrace | Token::LBracket => {
272                // Skip a compound value by tracking nesting depth
273                let mut depth = 1;
274                while depth > 0 {
275                    let token = self.read_token(wip)?;
276                    match token.node {
277                        Token::LBrace | Token::LBracket => {
278                            depth += 1;
279                        }
280                        Token::RBrace | Token::RBracket => {
281                            depth -= 1;
282                        }
283                        _ => {
284                            // primitives, commas, colons, strings, numbers, etc.
285                        }
286                    }
287                }
288                Ok(())
289            }
290            Token::String(_)
291            | Token::F64(_)
292            | Token::I64(_)
293            | Token::U64(_)
294            | Token::True
295            | Token::False
296            | Token::Null => {
297                // Primitive value; nothing more to skip
298                Ok(())
299            }
300            other => {
301                // Unexpected token when skipping a value
302                Err(JsonError::new(
303                    JsonErrorKind::UnexpectedToken {
304                        got: other,
305                        wanted: "value",
306                    },
307                    self.input,
308                    self.last_span,
309                    wip.path(),
310                ))
311            }
312        }
313    }
314
315    fn value<'facet>(&mut self, mut wip: Wip<'facet>) -> Result<Wip<'facet>, JsonError<'a>> {
316        let token = self.read_token(&wip)?;
317        match token.node {
318            Token::Null => {
319                let path = wip.path();
320                wip.put_default()
321                    .map_err(|e| JsonError::new_reflect(e, self.input, self.last_span, path))
322            }
323            _ => {
324                if matches!(wip.shape().def, Def::Option(_)) {
325                    trace!("Starting Some(_) option for {}", wip.shape().blue());
326                    let path = wip.path();
327                    wip = wip
328                        .push_some()
329                        .map_err(|e| JsonError::new_reflect(e, self.input, self.last_span, path))?;
330                    self.stack.push(Instruction::Pop(PopReason::Some))
331                }
332
333                match token.node {
334                    Token::Null => unreachable!(),
335                    Token::LBrace => {
336                        match wip.innermost_shape().def {
337                            Def::Map(_md) => {
338                                trace!("Object starting for map value ({})!", wip.shape().blue());
339                                let path = wip.path();
340                                wip = wip.put_default().map_err(|e| {
341                                    JsonError::new_reflect(e, self.input, self.last_span, path)
342                                })?;
343                            }
344                            Def::Enum(_ed) => {
345                                trace!("Object starting for enum value ({})!", wip.shape().blue());
346                                // nothing to do here
347                            }
348                            Def::Struct(_) => {
349                                trace!(
350                                    "Object starting for struct value ({})!",
351                                    wip.shape().blue()
352                                );
353                                // nothing to do here
354                            }
355                            _ => {
356                                let path = wip.path();
357                                return Err(JsonError::new(
358                                    JsonErrorKind::UnsupportedType {
359                                        got: wip.innermost_shape(),
360                                        wanted: "map, enum, or struct",
361                                    },
362                                    self.input,
363                                    self.last_span,
364                                    path,
365                                ));
366                            }
367                        }
368
369                        self.stack.push(Instruction::ObjectKeyOrObjectClose);
370                        Ok(wip)
371                    }
372                    Token::LBracket => {
373                        match wip.innermost_shape().def {
374                            Def::Array(_) => {
375                                trace!("Array starting for array ({})!", wip.shape().blue());
376                            }
377                            Def::Slice(_) => {
378                                trace!("Array starting for slice ({})!", wip.shape().blue());
379                            }
380                            Def::List(_) => {
381                                trace!("Array starting for list ({})!", wip.shape().blue());
382                                let path = wip.path();
383                                wip = wip.put_default().map_err(|e| {
384                                    JsonError::new_reflect(e, self.input, self.last_span, path)
385                                })?;
386                            }
387                            Def::Enum(_) => {
388                                trace!("Array starting for enum ({})!", wip.shape().blue());
389                            }
390                            Def::Struct(s) => {
391                                if s.kind == StructKind::Tuple {
392                                    trace!("Array starting for tuple ({})!", wip.shape().blue());
393                                    // Special handling for unit type ()
394                                    if s.fields.is_empty() {
395                                        // Check if the array is empty by peeking at the next token
396                                        let next_token = self.read_token(&wip)?;
397                                        if next_token.node == Token::RBracket {
398                                            // Empty array means unit type () - we're good
399                                            let path = wip.path();
400                                            wip = wip.put_default().map_err(|e| {
401                                                JsonError::new_reflect(
402                                                    e,
403                                                    self.input,
404                                                    self.last_span,
405                                                    path,
406                                                )
407                                            })?;
408                                        } else {
409                                            // Non-empty array is not valid for unit type
410                                            return Err(JsonError::new(
411                                                JsonErrorKind::UnsupportedType {
412                                                    got: wip.innermost_shape(),
413                                                    wanted: "empty array",
414                                                },
415                                                self.input,
416                                                self.last_span,
417                                                wip.path(),
418                                            ));
419                                        }
420                                    } else {
421                                        let path = wip.path();
422                                        wip = wip.put_default().map_err(|e| {
423                                            JsonError::new_reflect(
424                                                e,
425                                                self.input,
426                                                self.last_span,
427                                                path,
428                                            )
429                                        })?;
430                                    }
431                                } else {
432                                    return Err(JsonError::new(
433                                        JsonErrorKind::UnsupportedType {
434                                            got: wip.shape(),
435                                            wanted: "array, list, tuple, or slice",
436                                        },
437                                        self.input,
438                                        self.last_span,
439                                        wip.path(),
440                                    ));
441                                }
442                            }
443                            Def::Scalar(s) if matches!(s.affinity, ScalarAffinity::Empty(_)) => {
444                                trace!("Array starting for tuple ({})!", wip.shape().blue());
445                                // wip = wip.put_default().map_err(|e| JsonError::new_reflect(e, self.input, self.last_span, path))?;
446                                // Check if the array is empty by peeking at the next token
447                                let next_token = self.read_token(&wip)?;
448                                if next_token.node == Token::RBracket {
449                                    // Empty array means unit type () - we're good
450                                } else {
451                                    // Non-empty array is not valid for unit type
452                                    return Err(JsonError::new(
453                                        JsonErrorKind::UnsupportedType {
454                                            got: wip.innermost_shape(),
455                                            wanted: "empty array",
456                                        },
457                                        self.input,
458                                        self.last_span,
459                                        wip.path(),
460                                    ));
461                                }
462                            }
463                            _ => {
464                                return Err(JsonError::new(
465                                    JsonErrorKind::UnsupportedType {
466                                        got: wip.innermost_shape(),
467                                        wanted: "array, list, tuple, or slice",
468                                    },
469                                    self.input,
470                                    self.last_span,
471                                    wip.path(),
472                                ));
473                            }
474                        }
475
476                        trace!("Beginning pushback");
477                        self.stack.push(Instruction::ArrayItemOrArrayClose);
478                        let path = wip.path();
479                        wip.begin_pushback().map_err(|e| {
480                            JsonError::new_reflect(e, self.input, self.last_span, path)
481                        })
482                    }
483                    Token::RBrace | Token::RBracket | Token::Colon | Token::Comma => {
484                        Err(JsonError::new(
485                            JsonErrorKind::UnexpectedToken {
486                                got: token.node,
487                                wanted: "value",
488                            },
489                            self.input,
490                            self.last_span,
491                            wip.path(),
492                        ))
493                    }
494                    Token::String(s) => match wip.innermost_shape().def {
495                        Def::Scalar(_sd) => {
496                            let path = wip.path();
497                            wip.put::<String>(s).map_err(|e| {
498                                JsonError::new_reflect(e, self.input, self.last_span, path)
499                            })
500                        }
501                        Def::Enum(_ed) => {
502                            if wip.selected_variant().is_some() {
503                                trace!("Have variant selected arleady, just putting");
504
505                                // just put, then — if it's a tuple field it'll work
506                                let path = wip.path();
507                                wip.put::<String>(s).map_err(|e| {
508                                    JsonError::new_reflect(e, self.input, self.last_span, path)
509                                })
510                            } else {
511                                match wip.find_variant(&s) {
512                                    Some((variant_index, _)) => {
513                                        let path = wip.path();
514                                        wip.variant(variant_index).map_err(|e| {
515                                            JsonError::new_reflect(
516                                                e,
517                                                self.input,
518                                                self.last_span,
519                                                path,
520                                            )
521                                        })
522                                    }
523                                    None => Err(JsonError::new(
524                                        JsonErrorKind::NoSuchVariant {
525                                            name: s.to_string(),
526                                            enum_shape: wip.shape(),
527                                        },
528                                        self.input,
529                                        self.last_span,
530                                        wip.path(),
531                                    )),
532                                }
533                            }
534                        }
535                        _ => Err(JsonError::new(
536                            JsonErrorKind::UnsupportedType {
537                                got: wip.innermost_shape(),
538                                wanted: "enum or string",
539                            },
540                            self.input,
541                            self.last_span,
542                            wip.path(),
543                        )),
544                    },
545                    Token::F64(n) => {
546                        if wip.innermost_shape() == <f32 as Facet>::SHAPE {
547                            let path = wip.path();
548                            wip.put(n as f32).map_err(|e| {
549                                JsonError::new_reflect(e, self.input, self.last_span, path)
550                            })
551                        } else {
552                            let path = wip.path();
553                            wip.put(n).map_err(|e| {
554                                JsonError::new_reflect(e, self.input, self.last_span, path)
555                            })
556                        }
557                    }
558                    Token::U64(n) => {
559                        let path = wip.path();
560                        wip.put(n).map_err(|e| {
561                            JsonError::new_reflect(e, self.input, self.last_span, path)
562                        })
563                    }
564                    Token::I64(n) => {
565                        let path = wip.path();
566                        wip.put(n).map_err(|e| {
567                            JsonError::new_reflect(e, self.input, self.last_span, path)
568                        })
569                    }
570                    Token::True => {
571                        let path = wip.path();
572                        wip.put::<bool>(true).map_err(|e| {
573                            JsonError::new_reflect(e, self.input, self.last_span, path)
574                        })
575                    }
576                    Token::False => {
577                        let path = wip.path();
578                        wip.put::<bool>(false).map_err(|e| {
579                            JsonError::new_reflect(e, self.input, self.last_span, path)
580                        })
581                    }
582                    Token::EOF => Err(JsonError::new(
583                        JsonErrorKind::UnexpectedEof("in value"),
584                        self.input,
585                        self.last_span,
586                        wip.path(),
587                    )),
588                }
589            }
590        }
591    }
592
593    fn object_key_or_object_close<'f>(
594        &mut self,
595        mut wip: Wip<'f>,
596    ) -> Result<Wip<'f>, JsonError<'a>> {
597        let token = self.read_token(&wip)?;
598        match token.node {
599            Token::String(key) => {
600                trace!("Parsed object key: {}", key);
601
602                let mut ignore = false;
603                let mut needs_pop = true;
604                let mut handled_by_flatten = false;
605
606                match wip.shape().def {
607                    Def::Struct(sd) => {
608                        // First try to find a direct field match
609                        if let Some(index) = wip.field_index(&key) {
610                            trace!("It's a struct field");
611                            let path = wip.path();
612                            wip = wip.field(index).map_err(|e| {
613                                JsonError::new_reflect(e, self.input, self.last_span, path)
614                            })?;
615                        } else {
616                            // Check for flattened fields
617                            let mut found_in_flatten = false;
618                            for (index, field) in sd.fields.iter().enumerate() {
619                                if field.has_arbitrary_attr("flatten") {
620                                    trace!("Found flattened field #{}", index);
621                                    // Enter the flattened field
622                                    let path = wip.path();
623                                    wip = wip.field(index).map_err(|e| {
624                                        JsonError::new_reflect(e, self.input, self.last_span, path)
625                                    })?;
626
627                                    // Check if this flattened field has the requested key
628                                    if let Some(subfield_index) = wip.field_index(&key) {
629                                        trace!("Found key {} in flattened field", key);
630                                        let path = wip.path();
631                                        wip = wip.field(subfield_index).map_err(|e| {
632                                            JsonError::new_reflect(
633                                                e,
634                                                self.input,
635                                                self.last_span,
636                                                path,
637                                            )
638                                        })?;
639                                        found_in_flatten = true;
640                                        handled_by_flatten = true;
641                                        break;
642                                    } else if let Some((_variant_index, _variant)) =
643                                        wip.find_variant(&key)
644                                    {
645                                        trace!("Found key {} in flattened field", key);
646                                        let path = wip.path();
647                                        wip = wip.variant_named(&key).map_err(|e| {
648                                            JsonError::new_reflect(
649                                                e,
650                                                self.input,
651                                                self.last_span,
652                                                path,
653                                            )
654                                        })?;
655                                        found_in_flatten = true;
656                                        break;
657                                    } else {
658                                        // Key not in this flattened field, go back up
659                                        let path = wip.path();
660                                        wip = wip.pop().map_err(|e| {
661                                            JsonError::new_reflect(
662                                                e,
663                                                self.input,
664                                                self.last_span,
665                                                path,
666                                            )
667                                        })?;
668                                    }
669                                }
670                            }
671
672                            if !found_in_flatten {
673                                if wip.shape().has_deny_unknown_fields_attr() {
674                                    trace!(
675                                        "It's not a struct field AND we're denying unknown fields"
676                                    );
677                                    return Err(JsonError::new(
678                                        JsonErrorKind::UnknownField {
679                                            field_name: key.to_string(),
680                                            shape: wip.shape(),
681                                        },
682                                        self.input,
683                                        self.last_span,
684                                        wip.path(),
685                                    ));
686                                } else {
687                                    trace!(
688                                        "It's not a struct field and we're ignoring unknown fields"
689                                    );
690                                    ignore = true;
691                                }
692                            }
693                        }
694                    }
695                    Def::Enum(_ed) => match wip.find_variant(&key) {
696                        Some((index, variant)) => {
697                            trace!("Variant {} selected", variant.name.blue());
698                            let path = wip.path();
699                            wip = wip.variant(index).map_err(|e| {
700                                JsonError::new_reflect(e, self.input, self.last_span, path)
701                            })?;
702                            needs_pop = false;
703                        }
704                        None => {
705                            if let Some(_variant_index) = wip.selected_variant() {
706                                trace!(
707                                    "Already have a variant selected, treating key as struct field of variant"
708                                );
709                                // Try to find the field index of the key within the selected variant
710                                if let Some(index) = wip.field_index(&key) {
711                                    trace!("Found field {} in selected variant", key.blue());
712                                    let path = wip.path();
713                                    wip = wip.field(index).map_err(|e| {
714                                        JsonError::new_reflect(e, self.input, self.last_span, path)
715                                    })?;
716                                } else if wip.shape().has_deny_unknown_fields_attr() {
717                                    trace!("Unknown field in variant and denying unknown fields");
718                                    return Err(JsonError::new(
719                                        JsonErrorKind::UnknownField {
720                                            field_name: key.to_string(),
721                                            shape: wip.shape(),
722                                        },
723                                        self.input,
724                                        self.last_span,
725                                        wip.path(),
726                                    ));
727                                } else {
728                                    trace!("Ignoring unknown field in variant");
729                                    ignore = true;
730                                }
731                            } else {
732                                return Err(JsonError::new(
733                                    JsonErrorKind::NoSuchVariant {
734                                        name: key.to_string(),
735                                        enum_shape: wip.shape(),
736                                    },
737                                    self.input,
738                                    self.last_span,
739                                    wip.path(),
740                                ));
741                            }
742                        }
743                    },
744                    Def::Map(_) => {
745                        let path = wip.path();
746                        wip = wip.push_map_key().map_err(|e| {
747                            JsonError::new_reflect(e, self.input, self.last_span, path)
748                        })?;
749                        let path = wip.path();
750                        wip = wip.put(key).map_err(|e| {
751                            JsonError::new_reflect(e, self.input, self.last_span, path)
752                        })?;
753                        let path = wip.path();
754                        wip = wip.push_map_value().map_err(|e| {
755                            JsonError::new_reflect(e, self.input, self.last_span, path)
756                        })?;
757                    }
758                    _ => {
759                        return Err(JsonError::new(
760                            JsonErrorKind::Unimplemented("object key for non-struct/map"),
761                            self.input,
762                            self.last_span,
763                            wip.path(),
764                        ));
765                    }
766                }
767
768                let colon = self.read_token(&wip)?;
769                if colon.node != Token::Colon {
770                    return Err(JsonError::new(
771                        JsonErrorKind::UnexpectedToken {
772                            got: colon.node,
773                            wanted: "colon",
774                        },
775                        self.input,
776                        self.last_span,
777                        wip.path(),
778                    ));
779                }
780                self.stack
781                    .push(Instruction::CommaThenObjectKeyOrObjectClose);
782                if ignore {
783                    self.stack.push(Instruction::SkipValue);
784                } else {
785                    if needs_pop && !handled_by_flatten {
786                        trace!("Pushing Pop insn to stack (ObjectVal)");
787                        self.stack.push(Instruction::Pop(PopReason::ObjectVal));
788                    } else if handled_by_flatten {
789                        // We need two pops for flattened fields - one for the field itself,
790                        // one for the containing struct
791                        trace!("Pushing Pop insn to stack (ObjectVal) for flattened field");
792                        self.stack.push(Instruction::Pop(PopReason::ObjectVal));
793                        self.stack.push(Instruction::Pop(PopReason::ObjectVal));
794                    }
795                    self.stack.push(Instruction::Value);
796                }
797                Ok(wip)
798            }
799            Token::RBrace => {
800                trace!("Object closing");
801                Ok(wip)
802            }
803            _ => Err(JsonError::new(
804                JsonErrorKind::UnexpectedToken {
805                    got: token.node,
806                    wanted: "object key or closing brace",
807                },
808                self.input,
809                self.last_span,
810                wip.path(),
811            )),
812        }
813    }
814
815    fn comma_then_object_key_or_object_close(
816        &mut self,
817        wip: &Wip<'_>,
818    ) -> Result<(), JsonError<'a>> {
819        let token = self.read_token(wip)?;
820        match token.node {
821            Token::Comma => {
822                trace!("Object comma");
823                self.stack.push(Instruction::ObjectKeyOrObjectClose);
824                Ok(())
825            }
826            Token::RBrace => {
827                trace!("Object close");
828                Ok(())
829            }
830            _ => Err(JsonError::new(
831                JsonErrorKind::UnexpectedToken {
832                    got: token.node,
833                    wanted: "comma",
834                },
835                self.input,
836                self.last_span,
837                wip.path(),
838            )),
839        }
840    }
841
842    fn array_item_or_array_close<'facet>(
843        &mut self,
844        mut wip: Wip<'facet>,
845    ) -> Result<Wip<'facet>, JsonError<'a>> {
846        let token = self.read_token(&wip)?;
847        match token.node {
848            Token::RBracket => {
849                trace!("Array close");
850                Ok(wip)
851            }
852            _ => {
853                trace!("Array item");
854                assert!(
855                    self.unread_token.is_none(),
856                    "Cannot put back more than one token at a time"
857                );
858                self.unread_token = Some(token);
859                let path = wip.path();
860                wip = wip
861                    .begin_pushback()
862                    .map_err(|e| JsonError::new_reflect(e, self.input, self.last_span, path))?;
863                let path = wip.path();
864                wip = wip
865                    .push()
866                    .map_err(|e| JsonError::new_reflect(e, self.input, self.last_span, path))?;
867
868                self.stack.push(Instruction::CommaThenArrayItemOrArrayClose);
869                trace!("Pushing Pop insn to stack (arrayitem)");
870                self.stack.push(Instruction::Pop(PopReason::ArrayItem));
871                self.stack.push(Instruction::Value);
872                Ok(wip)
873            }
874        }
875    }
876
877    fn comma_then_array_item_or_array_close<'facet>(
878        &mut self,
879        mut wip: Wip<'facet>,
880    ) -> Result<Wip<'facet>, JsonError<'a>> {
881        let token = self.read_token(&wip)?;
882        match token.node {
883            Token::RBracket => {
884                trace!("Array close");
885                Ok(wip)
886            }
887            Token::Comma => {
888                trace!("Array comma");
889                let path = wip.path();
890                wip = wip
891                    .push()
892                    .map_err(|e| JsonError::new_reflect(e, self.input, self.last_span, path))?;
893                self.stack.push(Instruction::CommaThenArrayItemOrArrayClose);
894                trace!("Pushing Pop insn to stack (arrayitem)");
895                self.stack.push(Instruction::Pop(PopReason::ArrayItem));
896                self.stack.push(Instruction::Value);
897                Ok(wip)
898            }
899            _ => Err(JsonError::new(
900                JsonErrorKind::UnexpectedToken {
901                    got: token.node,
902                    wanted: "comma or closing bracket",
903                },
904                self.input,
905                self.last_span,
906                wip.path(),
907            )),
908        }
909    }
910
911    fn read_token(&mut self, wip: &Wip<'_>) -> Result<Spanned<Token>, JsonError<'a>> {
912        if let Some(token) = self.unread_token.take() {
913            self.last_span = token.span;
914            Ok(token)
915        } else {
916            match self.tokenizer.next_token() {
917                Ok(token) => {
918                    self.last_span = token.span;
919                    Ok(token)
920                }
921                Err(e) => {
922                    self.last_span = e.span;
923                    Err(JsonError::new_syntax(
924                        e.kind,
925                        self.input,
926                        self.last_span,
927                        wip.path(),
928                    ))
929                }
930            }
931        }
932    }
933}