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}