facet_json/
deserialize.rs

1use core::num::{
2    NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroIsize, NonZeroU8, NonZeroU16, NonZeroU32,
3    NonZeroU64, NonZeroUsize,
4};
5
6use facet_core::{Characteristic, Def, Facet, FieldAttribute, ScalarAffinity, ShapeAttribute};
7use facet_reflect::{HeapValue, Wip};
8use log::trace;
9
10use alloc::format;
11use alloc::string::{String, ToString};
12use alloc::vec::Vec;
13use owo_colors::OwoColorize;
14
15mod error;
16pub use error::*;
17
18/// Deserializes a JSON string into a value of type `T` that implements `Facet`.
19///
20/// This function takes a JSON string representation and converts it into a Rust
21/// value of the specified type `T`. The type must implement the `Facet` trait
22/// to provide the necessary type information for deserialization.
23pub fn from_str<T: Facet>(json: &str) -> Result<T, JsonParseErrorWithContext<'_>> {
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<T: Facet>(json: &[u8]) -> Result<T, JsonParseErrorWithContext<'_>> {
37    let wip = Wip::alloc::<T>();
38    let heap_value = from_slice_wip(wip, json)?;
39    Ok(heap_value.materialize::<T>().unwrap())
40}
41
42/// Deserialize a JSON string into a Wip object.
43///
44/// # Arguments
45///
46/// * `wip` - A mutable Wip object to deserialize into.
47/// * `input` - A byte slice representing the JSON input.
48///
49/// # Returns
50///
51/// A result containing the updated `Wip` or a `JsonParseErrorWithContext`.
52pub fn from_slice_wip<'input, 'a>(
53    mut wip: Wip<'a>,
54    input: &'input [u8],
55) -> Result<HeapValue<'a>, JsonParseErrorWithContext<'input>> {
56    let mut pos = 0;
57
58    macro_rules! err {
59        ($kind:expr) => {
60            Err(JsonParseErrorWithContext::new(
61                $kind,
62                input,
63                pos,
64                wip.path(),
65            ))
66        };
67    }
68    macro_rules! bail {
69        ($kind:expr) => {
70            return err!($kind)
71        };
72    }
73
74    /// Indicates why we are expecting a value in the parsing stack.
75    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
76    enum WhyValue {
77        /// At the top level of the JSON input.
78        TopLevel,
79        /// Expecting an object key.
80        ObjectKey,
81        /// Expecting an object value.
82        ObjectValue,
83        /// Expecting an array element.
84        ArrayElement,
85    }
86
87    /// Indicates the context for a comma separator in JSON (object or array).
88    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
89    enum WhyComma {
90        /// A comma in an object context.
91        Object,
92        /// A comma in an array context.
93        Array,
94    }
95
96    /// Indicates the type of separator expected (colon or comma).
97    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
98    enum Separator {
99        /// Expecting a colon separator in object key-value pairs.
100        Colon,
101        /// Expecting a comma separator (in objects or arrays).
102        Comma(WhyComma),
103    }
104
105    /// Represents the next expected token or structure while parsing.
106    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
107    enum Expect {
108        /// Expecting a value, with its reason/context.
109        Value(WhyValue),
110        /// Expecting a separator (colon or comma).
111        Separator(Separator),
112        /// We did `push_some` and now we need to pop it
113        PopOption,
114    }
115
116    let mut stack: Vec<Expect> = Vec::new();
117    stack.push(Expect::Value(WhyValue::TopLevel));
118
119    loop {
120        // skip over whitespace
121        while let Some(c) = input.get(pos).copied() {
122            match c {
123                b' ' | b'\t' | b'\n' | b'\r' => {
124                    pos += 1;
125                }
126                _ => break,
127            }
128        }
129
130        let frame_count = wip.frames_count();
131        let expect = match stack.pop() {
132            Some(expect) => expect,
133            None => {
134                if frame_count == 1 {
135                    return Ok(wip.build().unwrap());
136                } else {
137                    trace!("frame_count isn't 1, it's {}", frame_count);
138                    bail!(JsonErrorKind::UnexpectedEof("frame_count isn't 1"));
139                }
140            }
141        };
142        trace!("[{frame_count}] Expecting {:?}", expect.yellow());
143
144        let Some(c) = input.get(pos).copied() else {
145            bail!(JsonErrorKind::UnexpectedEof("no input at pos"));
146        };
147
148        let mut finished_value: Option<WhyValue> = None;
149
150        match expect {
151            Expect::PopOption => {
152                // that's all, carry on
153                trace!("Popping option");
154                finished_value = Some(WhyValue::ObjectValue);
155            }
156            Expect::Value(why) => {
157                if let Def::Option(_) = wip.shape().def {
158                    wip = wip.push_some().unwrap();
159                    stack.push(Expect::PopOption);
160                }
161
162                match c {
163                    b'{' => {
164                        trace!("Object starting");
165                        pos += 1;
166                        let Some(c) = input.get(pos).copied() else {
167                            bail!(JsonErrorKind::UnexpectedEof("nothing after {"));
168                        };
169                        match c {
170                            b'}' => {
171                                trace!("Empty object ended");
172                                pos += 1;
173                                finished_value = Some(why);
174                            }
175                            _ => {
176                                trace!("Object's not empty, let's do `key: value ,` next");
177                                // okay, next we expect a "key: value"
178                                stack.push(Expect::Separator(Separator::Comma(WhyComma::Object)));
179                                stack.push(Expect::Value(WhyValue::ObjectValue));
180                                stack.push(Expect::Separator(Separator::Colon));
181                                stack.push(Expect::Value(WhyValue::ObjectKey));
182                            }
183                        }
184                    }
185                    b'[' => {
186                        pos += 1;
187                        let Some(c) = input.get(pos).copied() else {
188                            bail!(JsonErrorKind::UnexpectedEof("nothing after ["));
189                        };
190
191                        wip = wip.begin_pushback().unwrap();
192                        match c {
193                            b']' => {
194                                // an array just closed, somewhere
195                                pos += 1;
196                                trace!("Got empty array");
197                                finished_value = Some(why);
198                            }
199                            _ => {
200                                // okay, next we expect an item and a separator (or the end of the array)
201                                stack.push(Expect::Separator(Separator::Comma(WhyComma::Array)));
202                                stack.push(Expect::Value(WhyValue::ArrayElement));
203                                wip = wip.push().unwrap();
204                                continue; // we didn't finish a value so don't pop yet
205                            }
206                        }
207                    }
208                    b'"' => {
209                        pos += 1;
210                        // Our value is a string: collect bytes first
211                        let mut bytes = Vec::new();
212                        loop {
213                            let Some(c) = input.get(pos).copied() else {
214                                bail!(JsonErrorKind::UnexpectedEof("nothing after \""));
215                            };
216                            match c {
217                                b'"' => {
218                                    pos += 1;
219                                    break;
220                                }
221                                b'\\' => {
222                                    // Handle escape sequences
223                                    pos += 1;
224                                    if let Some(next) = input.get(pos) {
225                                        bytes.push(*next);
226                                        pos += 1;
227                                    } else {
228                                        bail!(JsonErrorKind::UnexpectedEof("nothing after \\"));
229                                    }
230                                }
231                                _ => {
232                                    bytes.push(c);
233                                    pos += 1;
234                                }
235                            }
236                        }
237
238                        // Convert collected bytes to string at once
239                        let value = match core::str::from_utf8(&bytes) {
240                            Ok(s) => s.to_string(),
241                            Err(e) => {
242                                bail!(JsonErrorKind::InvalidUtf8(format!(
243                                    "Invalid UTF-8 sequence: {}",
244                                    e
245                                )))
246                            }
247                        };
248
249                        trace!(
250                            "Parsed string {:?} for {} (why? {:?})",
251                            value.yellow(),
252                            wip.shape().blue(),
253                            why.cyan()
254                        );
255
256                        match why {
257                            WhyValue::TopLevel | WhyValue::ArrayElement | WhyValue::ObjectValue => {
258                                wip = wip.parse(&value).unwrap();
259                                finished_value = Some(why);
260                            }
261                            WhyValue::ObjectKey => {
262                                // Look for field with matching name or rename attribute
263                                let shape = wip.shape();
264
265                                if let Def::Struct(struct_def) = shape.def {
266                                    let field = struct_def.fields.iter().find(|f| {
267                                        // Check original name
268                                        if f.name == value {
269                                            return true;
270                                        }
271
272                                        // Check rename attribute
273                                        f.attributes.iter().any(|attr| {
274                                            if let FieldAttribute::Rename(rename) = attr {
275                                                rename == &value
276                                            } else {
277                                                false
278                                            }
279                                        })
280                                    });
281
282                                    if let Some(field) = field {
283                                        trace!("found field {:?}", field.blue());
284                                        wip = wip.field_named(field.name).unwrap();
285                                    } else if shape.attributes.iter().any(|attr| {
286                                        matches!(attr, ShapeAttribute::DenyUnknownFields)
287                                    }) {
288                                        // Field not found - original or renamed, and unknown fields denied
289                                        bail!(JsonErrorKind::UnknownField(value.to_string()));
290                                    } else {
291                                        // pop Expect::Colon (assert)
292                                        let expect_colon = stack.pop();
293                                        assert!(matches!(
294                                            expect_colon,
295                                            Some(Expect::Separator(Separator::Colon))
296                                        ));
297                                        // skip over whitespace
298                                        while let Some(b' ' | b'\t' | b'\n' | b'\r') =
299                                            input.get(pos).copied()
300                                        {
301                                            pos += 1;
302                                        }
303                                        // skip over colon
304                                        if let Some(b':') = input.get(pos) {
305                                            pos += 1;
306                                        } else {
307                                            bail!(JsonErrorKind::UnexpectedCharacter(
308                                                input
309                                                    .get(pos)
310                                                    .copied()
311                                                    .map(|c| c as char)
312                                                    .unwrap_or('\0')
313                                            ));
314                                        }
315                                        // skip over whitespace
316                                        while let Some(b' ' | b'\t' | b'\n' | b'\r') =
317                                            input.get(pos).copied()
318                                        {
319                                            pos += 1;
320                                        }
321                                        // pop Expect::Value
322                                        let expect_value = stack.pop();
323                                        assert!(matches!(
324                                            expect_value,
325                                            Some(Expect::Value(WhyValue::ObjectValue))
326                                        ));
327                                        // skip over value
328                                        skip_over_value(&mut pos, input).map_err(|e| {
329                                            JsonParseErrorWithContext::new(
330                                                e,
331                                                input,
332                                                pos,
333                                                wip.path(),
334                                            )
335                                        })?;
336                                        trace!(
337                                            "immediately after skip over value, we're at pos {}, char is {}",
338                                            pos,
339                                            input.get(pos).copied().unwrap_or(b'$') as char
340                                        );
341                                    }
342                                } else {
343                                    trace!(
344                                        "Getting field {}, not in a Struct, but in a... {}",
345                                        value.blue(),
346                                        wip.shape()
347                                    );
348                                    wip = wip.field_named(&value).expect("assuming only structs have a fixed set of fields (which is not true, cf. enums)");
349                                }
350                            }
351                        }
352                    }
353                    b'0'..=b'9' | b'-' => {
354                        pos += 1;
355                        let start = pos - 1;
356                        while let Some(c) = input.get(pos) {
357                            match c {
358                                b'0'..=b'9' | b'.' => {
359                                    pos += 1;
360                                }
361                                _ => break,
362                            }
363                        }
364                        let number = &input[start..pos];
365                        let number = core::str::from_utf8(number).unwrap();
366                        let number = number.parse::<f64>().unwrap();
367                        trace!("Parsed {:?}", number.yellow());
368
369                        let shape = wip.shape();
370                        match shape.def {
371                            Def::Scalar(sd) => match sd.affinity {
372                                ScalarAffinity::Number(_na) => {
373                                    if shape.is_type::<u8>() {
374                                        if number >= 0.0 && number <= u8::MAX as f64 {
375                                            let value = number as u8;
376                                            wip = wip.put::<u8>(value).unwrap();
377                                        } else {
378                                            bail!(JsonErrorKind::NumberOutOfRange(number));
379                                        }
380                                    } else if shape.is_type::<u16>() {
381                                        if number >= 0.0 && number <= u16::MAX as f64 {
382                                            let value = number as u16;
383                                            wip = wip.put::<u16>(value).unwrap();
384                                        } else {
385                                            bail!(JsonErrorKind::NumberOutOfRange(number));
386                                        }
387                                    } else if shape.is_type::<u32>() {
388                                        if number >= 0.0 && number <= u32::MAX as f64 {
389                                            let value = number as u32;
390                                            wip = wip.put::<u32>(value).unwrap();
391                                        } else {
392                                            bail!(JsonErrorKind::NumberOutOfRange(number));
393                                        }
394                                    } else if shape.is_type::<u64>() {
395                                        if number >= 0.0 && number <= u64::MAX as f64 {
396                                            let value = number as u64;
397                                            wip = wip.put::<u64>(value).unwrap();
398                                        } else {
399                                            bail!(JsonErrorKind::NumberOutOfRange(number));
400                                        }
401                                    } else if shape.is_type::<i8>() {
402                                        if number >= i8::MIN as f64 && number <= i8::MAX as f64 {
403                                            let value = number as i8;
404                                            wip = wip.put::<i8>(value).unwrap();
405                                        } else {
406                                            bail!(JsonErrorKind::NumberOutOfRange(number));
407                                        }
408                                    } else if shape.is_type::<i16>() {
409                                        if number >= i16::MIN as f64 && number <= i16::MAX as f64 {
410                                            let value = number as i16;
411                                            wip = wip.put::<i16>(value).unwrap();
412                                        } else {
413                                            bail!(JsonErrorKind::NumberOutOfRange(number));
414                                        }
415                                    } else if shape.is_type::<i32>() {
416                                        if number >= i32::MIN as f64 && number <= i32::MAX as f64 {
417                                            let value = number as i32;
418                                            wip = wip.put::<i32>(value).unwrap();
419                                        } else {
420                                            bail!(JsonErrorKind::NumberOutOfRange(number));
421                                        }
422                                    } else if shape.is_type::<i64>() {
423                                        // Note: f64 might lose precision for large i64 values, but this is a common limitation.
424                                        if number >= i64::MIN as f64 && number <= i64::MAX as f64 {
425                                            let value = number as i64;
426                                            wip = wip.put::<i64>(value).unwrap();
427                                        } else {
428                                            bail!(JsonErrorKind::NumberOutOfRange(number));
429                                        }
430                                    } else if shape.is_type::<f32>() {
431                                        if number >= f32::MIN as f64 && number <= f32::MAX as f64 {
432                                            let value = number as f32;
433                                            wip = wip.put::<f32>(value).unwrap();
434                                        } else {
435                                            bail!(JsonErrorKind::NumberOutOfRange(number));
436                                        }
437                                    } else if shape.is_type::<f64>() {
438                                        wip = wip.put::<f64>(number).unwrap();
439                                    } else if shape.is_type::<NonZeroU8>() {
440                                        if number >= 1.0 && number <= u8::MAX as f64 {
441                                            let value = NonZeroU8::new(number as u8).unwrap();
442                                            wip = wip.put::<NonZeroU8>(value).unwrap();
443                                        } else {
444                                            bail!(JsonErrorKind::NumberOutOfRange(number));
445                                        }
446                                    } else if shape.is_type::<NonZeroU16>() {
447                                        if number >= 1.0 && number <= u16::MAX as f64 {
448                                            let value = NonZeroU16::new(number as u16).unwrap();
449                                            wip = wip.put::<NonZeroU16>(value).unwrap();
450                                        } else {
451                                            bail!(JsonErrorKind::NumberOutOfRange(number));
452                                        }
453                                    } else if shape.is_type::<NonZeroU32>() {
454                                        if number >= 1.0 && number <= u32::MAX as f64 {
455                                            let value = NonZeroU32::new(number as u32).unwrap();
456                                            wip = wip.put::<NonZeroU32>(value).unwrap();
457                                        } else {
458                                            bail!(JsonErrorKind::NumberOutOfRange(number));
459                                        }
460                                    } else if shape.is_type::<NonZeroU64>() {
461                                        if number >= 1.0 && number <= u64::MAX as f64 {
462                                            let value = NonZeroU64::new(number as u64).unwrap();
463                                            wip = wip.put::<NonZeroU64>(value).unwrap();
464                                        } else {
465                                            bail!(JsonErrorKind::NumberOutOfRange(number));
466                                        }
467                                    } else if shape.is_type::<NonZeroUsize>() {
468                                        if number >= 1.0 && number <= usize::MAX as f64 {
469                                            let value = NonZeroUsize::new(number as usize).unwrap();
470                                            wip = wip.put::<NonZeroUsize>(value).unwrap();
471                                        } else {
472                                            bail!(JsonErrorKind::NumberOutOfRange(number));
473                                        }
474                                    } else if shape.is_type::<NonZeroI8>() {
475                                        if number >= 1.0 && number <= i8::MAX as f64 {
476                                            let value = NonZeroI8::new(number as i8).unwrap();
477                                            wip = wip.put::<NonZeroI8>(value).unwrap();
478                                        } else {
479                                            bail!(JsonErrorKind::NumberOutOfRange(number));
480                                        }
481                                    } else if shape.is_type::<NonZeroI16>() {
482                                        if number >= 1.0 && number <= i16::MAX as f64 {
483                                            let value = NonZeroI16::new(number as i16).unwrap();
484                                            wip = wip.put::<NonZeroI16>(value).unwrap();
485                                        } else {
486                                            bail!(JsonErrorKind::NumberOutOfRange(number));
487                                        }
488                                    } else if shape.is_type::<NonZeroI32>() {
489                                        if number >= 1.0 && number <= i32::MAX as f64 {
490                                            let value = NonZeroI32::new(number as i32).unwrap();
491                                            wip = wip.put::<NonZeroI32>(value).unwrap();
492                                        } else {
493                                            bail!(JsonErrorKind::NumberOutOfRange(number));
494                                        }
495                                    } else if shape.is_type::<NonZeroI64>() {
496                                        if number >= 1.0 && number <= i64::MAX as f64 {
497                                            let value = NonZeroI64::new(number as i64).unwrap();
498                                            wip = wip.put::<NonZeroI64>(value).unwrap();
499                                        } else {
500                                            bail!(JsonErrorKind::NumberOutOfRange(number));
501                                        }
502                                    } else if shape.is_type::<NonZeroIsize>() {
503                                        if number >= 1.0 && number <= isize::MAX as f64 {
504                                            let value = NonZeroIsize::new(number as isize).unwrap();
505                                            wip = wip.put::<NonZeroIsize>(value).unwrap();
506                                        } else {
507                                            bail!(JsonErrorKind::NumberOutOfRange(number));
508                                        }
509                                    } else {
510                                        todo!("number type, but unknown")
511                                    }
512                                }
513                                ScalarAffinity::String(_sa) => {
514                                    if shape.is_type::<String>() {
515                                        let value = number.to_string();
516                                        bail!(JsonErrorKind::StringAsNumber(value));
517                                    } else {
518                                        todo!()
519                                    }
520                                }
521                                _ => {
522                                    todo!("saw number in JSON but expected.. shape {}?", shape)
523                                }
524                            },
525                            _ => {
526                                todo!("saw number in JSON but expected.. shape {}?", shape)
527                            }
528                        }
529                        finished_value = Some(why);
530                    }
531                    b't' | b'f' => {
532                        // Boolean: true or false
533                        if input[pos..].starts_with(b"true") {
534                            pos += 4;
535                            let shape = wip.shape();
536                            match shape.def {
537                                Def::Scalar(sd) => match sd.affinity {
538                                    ScalarAffinity::Boolean(_) => {
539                                        wip = wip.put::<bool>(true).unwrap();
540                                    }
541                                    _ => {
542                                        bail!(JsonErrorKind::UnexpectedCharacter('t'));
543                                    }
544                                },
545                                _ => {
546                                    bail!(JsonErrorKind::UnexpectedCharacter('t'));
547                                }
548                            }
549                            finished_value = Some(why);
550                        } else if input[pos..].starts_with(b"false") {
551                            pos += 5;
552                            let shape = wip.shape();
553                            match shape.def {
554                                Def::Scalar(sd) => match sd.affinity {
555                                    ScalarAffinity::Boolean(_) => {
556                                        wip = wip.put::<bool>(false).unwrap();
557                                    }
558                                    _ => {
559                                        bail!(JsonErrorKind::UnexpectedCharacter('f'));
560                                    }
561                                },
562                                _ => {
563                                    bail!(JsonErrorKind::UnexpectedCharacter('f'));
564                                }
565                            }
566                            finished_value = Some(why);
567                        } else {
568                            bail!(JsonErrorKind::UnexpectedCharacter(c as char));
569                        }
570                    }
571                    b'n' => {
572                        // wow it's a null — probably
573                        let slice_rest = &input[pos..];
574                        if slice_rest.starts_with(b"null") {
575                            pos += 4;
576
577                            // ok but we already pushed some! luckily wip has the method for us
578                            wip = wip.pop_some_push_none().unwrap();
579                            finished_value = Some(why);
580                        } else {
581                            bail!(JsonErrorKind::UnexpectedCharacter('n'));
582                        }
583                    }
584                    c => {
585                        bail!(JsonErrorKind::UnexpectedCharacter(c as char));
586                    }
587                }
588            }
589            Expect::Separator(separator) => match separator {
590                Separator::Colon => match c {
591                    b':' => {
592                        pos += 1;
593                    }
594                    _ => {
595                        bail!(JsonErrorKind::UnexpectedCharacter(c as char));
596                    }
597                },
598                Separator::Comma(why) => match c {
599                    b',' => {
600                        pos += 1;
601                        match why {
602                            WhyComma::Array => {
603                                stack.push(Expect::Separator(Separator::Comma(WhyComma::Array)));
604                                stack.push(Expect::Value(WhyValue::ArrayElement));
605                                wip = wip.push().unwrap();
606                            }
607                            WhyComma::Object => {
608                                // looks like we're in for another round of object parsing
609                                stack.push(Expect::Separator(Separator::Comma(WhyComma::Object)));
610                                stack.push(Expect::Value(WhyValue::ObjectValue));
611                                stack.push(Expect::Separator(Separator::Colon));
612                                stack.push(Expect::Value(WhyValue::ObjectKey));
613                            }
614                        }
615                    }
616                    b'}' => match why {
617                        WhyComma::Object => {
618                            pos += 1;
619                            finished_value = Some(WhyValue::ObjectValue);
620                        }
621                        _ => {
622                            bail!(JsonErrorKind::UnexpectedCharacter(c as char));
623                        }
624                    },
625                    b']' => {
626                        pos += 1;
627                        match why {
628                            WhyComma::Array => {
629                                // we finished the array, neat
630                                if frame_count > 1 {
631                                    wip = wip.pop().unwrap();
632                                }
633                            }
634                            _ => {
635                                bail!(JsonErrorKind::UnexpectedCharacter(c as char));
636                            }
637                        }
638                    }
639                    _ => {
640                        bail!(JsonErrorKind::UnexpectedCharacter(c as char));
641                    }
642                },
643            },
644        }
645
646        if let Some(why) = finished_value {
647            trace!("Just finished value because of {:?}", why.green());
648            match why {
649                WhyValue::ObjectKey => {}
650                WhyValue::TopLevel | WhyValue::ObjectValue | WhyValue::ArrayElement => {
651                    trace!("Shape before popping: {}", wip.shape());
652
653                    let struct_has_default = wip
654                        .shape()
655                        .attributes
656                        .iter()
657                        .any(|attr| matches!(attr, ShapeAttribute::Default));
658                    let mut has_missing_fields = false;
659
660                    // Ensure all struct fields are set before popping
661                    if let Def::Struct(sd) = wip.shape().def {
662                        for i in 0..sd.fields.len() {
663                            if !wip.is_field_set(i).unwrap() {
664                                let missing_field: &'static str = sd.fields[i].name;
665                                if struct_has_default {
666                                    has_missing_fields = true;
667                                } else {
668                                    let field = sd.fields[i];
669                                    if let Some(attr) =
670                                        field.attributes.iter().find_map(|attr| match attr {
671                                            FieldAttribute::Default(d) => Some(d),
672                                            _ => None,
673                                        })
674                                    {
675                                        match attr {
676                                            Some(fun) => {
677                                                wip = wip
678                                                    .field(i)
679                                                    .unwrap()
680                                                    .put_from_fn(*fun)
681                                                    .unwrap()
682                                                    .pop()
683                                                    .unwrap();
684                                            }
685                                            None => {
686                                                wip = wip
687                                                    .field(i)
688                                                    .unwrap()
689                                                    .put_default()
690                                                    .unwrap()
691                                                    .pop()
692                                                    .unwrap();
693                                            }
694                                        }
695                                    } else {
696                                        bail!(JsonErrorKind::MissingField(missing_field));
697                                    }
698                                }
699                            }
700                        }
701                    }
702
703                    if has_missing_fields {
704                        trace!("struct has missing fields but we have default");
705                        if !wip.shape().is(Characteristic::Default) {
706                            todo!(
707                                "Default struct has missing fields, the `default` impl but it does not implement Default"
708                            )
709                        }
710                        let default_struct_val = Wip::alloc_shape(wip.shape())
711                            .put_default()
712                            .unwrap()
713                            .build()
714                            .unwrap();
715                        let peek = default_struct_val.peek().into_struct().unwrap();
716
717                        // For every missing field, take it from the peek and copy it into the wip
718                        if let Def::Struct(sd) = wip.shape().def {
719                            for i in 0..sd.fields.len() {
720                                if !wip.is_field_set(i).unwrap() {
721                                    let field_value = peek.field(i).unwrap();
722                                    wip = wip
723                                        .field(i)
724                                        .unwrap()
725                                        .put_peek(field_value)
726                                        .unwrap()
727                                        .pop()
728                                        .unwrap();
729                                }
730                            }
731                        }
732                    }
733
734                    if frame_count == 1 {
735                        return Ok(wip.build().unwrap());
736                    } else {
737                        wip = wip.pop().unwrap();
738                    }
739                }
740            }
741        }
742    }
743}
744
745fn skip_over_value(pos: &mut usize, input: &[u8]) -> Result<(), JsonErrorKind> {
746    let bytes = input;
747
748    // Helper for skipping whitespace
749    let skip_whitespace = |pos: &mut usize| {
750        while *pos < bytes.len() {
751            match bytes[*pos] {
752                b' ' | b'\t' | b'\n' | b'\r' => *pos += 1,
753                _ => break,
754            }
755        }
756    };
757
758    skip_whitespace(pos);
759
760    if *pos >= bytes.len() {
761        return Err(JsonErrorKind::UnexpectedEof(
762            "while skipping over value: input ended unexpectedly at root",
763        ));
764    }
765
766    match bytes[*pos] {
767        b'{' => {
768            // Skip a full object, recursively
769            *pos += 1;
770            skip_whitespace(pos);
771            if *pos < bytes.len() && bytes[*pos] == b'}' {
772                *pos += 1;
773                return Ok(());
774            }
775            loop {
776                // Skip key
777                skip_over_value(pos, input)?;
778                skip_whitespace(pos);
779                // Expect colon between key and value
780                if *pos >= bytes.len() || bytes[*pos] != b':' {
781                    return Err(JsonErrorKind::UnexpectedEof(
782                        "while skipping over value: object key with no colon or input ended",
783                    ));
784                }
785                *pos += 1;
786                skip_whitespace(pos);
787                // Skip value
788                skip_over_value(pos, input)?;
789                skip_whitespace(pos);
790                if *pos >= bytes.len() {
791                    return Err(JsonErrorKind::UnexpectedEof(
792                        "while skipping over value: object value with EOF after",
793                    ));
794                }
795                if bytes[*pos] == b'}' {
796                    *pos += 1;
797                    break;
798                } else if bytes[*pos] == b',' {
799                    *pos += 1;
800                    skip_whitespace(pos);
801                    continue;
802                } else {
803                    return Err(JsonErrorKind::UnexpectedCharacter(bytes[*pos] as char));
804                }
805            }
806        }
807        b'[' => {
808            // Skip a full array, recursively
809            *pos += 1;
810            skip_whitespace(pos);
811            if *pos < bytes.len() && bytes[*pos] == b']' {
812                *pos += 1;
813                return Ok(());
814            }
815            loop {
816                skip_over_value(pos, input)?;
817                skip_whitespace(pos);
818                if *pos >= bytes.len() {
819                    return Err(JsonErrorKind::UnexpectedEof(
820                        "while skipping over value: EOF inside array",
821                    ));
822                }
823                if bytes[*pos] == b']' {
824                    *pos += 1;
825                    break;
826                } else if bytes[*pos] == b',' {
827                    *pos += 1;
828                    skip_whitespace(pos);
829                    continue;
830                } else {
831                    return Err(JsonErrorKind::UnexpectedCharacter(bytes[*pos] as char));
832                }
833            }
834        }
835        b'"' => {
836            // Skip a string, with escape processing
837            *pos += 1;
838            while *pos < bytes.len() {
839                match bytes[*pos] {
840                    b'\\' => {
841                        // Could have EOF after backslash
842                        if *pos + 1 >= bytes.len() {
843                            return Err(JsonErrorKind::UnexpectedEof(
844                                "while skipping over value: EOF after backslash in string",
845                            ));
846                        }
847                        *pos += 2; // Skip backslash and the next character (escaped)
848                    }
849                    b'"' => {
850                        *pos += 1;
851                        break;
852                    }
853                    _ => {
854                        *pos += 1;
855                    }
856                }
857            }
858            if *pos > bytes.len() {
859                return Err(JsonErrorKind::UnexpectedEof(
860                    "while skipping over value: string ended unexpectedly",
861                ));
862            }
863        }
864        b't' => {
865            // Expect "true"
866            if bytes.len() >= *pos + 4 && &bytes[*pos..*pos + 4] == b"true" {
867                *pos += 4;
868            } else {
869                return Err(JsonErrorKind::UnexpectedCharacter('t'));
870            }
871        }
872        b'f' => {
873            // Expect "false"
874            if bytes.len() >= *pos + 5 && &bytes[*pos..*pos + 5] == b"false" {
875                *pos += 5;
876            } else {
877                return Err(JsonErrorKind::UnexpectedCharacter('f'));
878            }
879        }
880        b'n' => {
881            // Expect "null"
882            if bytes.len() >= *pos + 4 && &bytes[*pos..*pos + 4] == b"null" {
883                *pos += 4;
884            } else {
885                return Err(JsonErrorKind::UnexpectedCharacter('n'));
886            }
887        }
888        b'-' | b'0'..=b'9' => {
889            // Skip a number: -?\d+(\.\d+)?([eE][+-]?\d+)?
890            let start = *pos;
891            if bytes[*pos] == b'-' {
892                *pos += 1;
893            }
894            if *pos < bytes.len() && bytes[*pos] == b'0' {
895                *pos += 1;
896            } else {
897                while *pos < bytes.len() && (bytes[*pos] as char).is_ascii_digit() {
898                    *pos += 1;
899                }
900            }
901            if *pos < bytes.len() && bytes[*pos] == b'.' {
902                *pos += 1;
903                let mut has_digit = false;
904                while *pos < bytes.len() && (bytes[*pos] as char).is_ascii_digit() {
905                    *pos += 1;
906                    has_digit = true;
907                }
908                if !has_digit {
909                    return Err(JsonErrorKind::UnexpectedCharacter('.'));
910                }
911            }
912            if *pos < bytes.len() && (bytes[*pos] == b'e' || bytes[*pos] == b'E') {
913                *pos += 1;
914                if *pos < bytes.len() && (bytes[*pos] == b'+' || bytes[*pos] == b'-') {
915                    *pos += 1;
916                }
917                let mut has_digit = false;
918                while *pos < bytes.len() && (bytes[*pos] as char).is_ascii_digit() {
919                    *pos += 1;
920                    has_digit = true;
921                }
922                if !has_digit {
923                    return Err(JsonErrorKind::UnexpectedCharacter('e'));
924                }
925            }
926            if *pos == start {
927                return Err(JsonErrorKind::UnexpectedCharacter(bytes[start] as char));
928            }
929        }
930        _ => {
931            return Err(JsonErrorKind::UnexpectedCharacter(bytes[*pos] as char));
932        }
933    }
934    Ok(())
935}