facet_json/deserialize.rs
1use core::num::{
2 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroIsize, NonZeroU8, NonZeroU16, NonZeroU32,
3 NonZeroU64, NonZeroUsize,
4};
5
6use facet_core::{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'n' => {
532 // wow it's a null — probably
533 let slice_rest = &input[pos..];
534 if slice_rest.starts_with(b"null") {
535 pos += 4;
536
537 // ok but we already pushed some! luckily wip has the method for us
538 wip = wip.pop_some_push_none().unwrap();
539 finished_value = Some(why);
540 } else {
541 bail!(JsonErrorKind::UnexpectedCharacter('n'));
542 }
543 }
544 c => {
545 bail!(JsonErrorKind::UnexpectedCharacter(c as char));
546 }
547 }
548 }
549 Expect::Separator(separator) => match separator {
550 Separator::Colon => match c {
551 b':' => {
552 pos += 1;
553 }
554 _ => {
555 bail!(JsonErrorKind::UnexpectedCharacter(c as char));
556 }
557 },
558 Separator::Comma(why) => match c {
559 b',' => {
560 pos += 1;
561 match why {
562 WhyComma::Array => {
563 stack.push(Expect::Separator(Separator::Comma(WhyComma::Array)));
564 stack.push(Expect::Value(WhyValue::ArrayElement));
565 wip = wip.push().unwrap();
566 }
567 WhyComma::Object => {
568 // looks like we're in for another round of object parsing
569 stack.push(Expect::Separator(Separator::Comma(WhyComma::Object)));
570 stack.push(Expect::Value(WhyValue::ObjectValue));
571 stack.push(Expect::Separator(Separator::Colon));
572 stack.push(Expect::Value(WhyValue::ObjectKey));
573 }
574 }
575 }
576 b'}' => match why {
577 WhyComma::Object => {
578 pos += 1;
579 finished_value = Some(WhyValue::ObjectValue);
580 }
581 _ => {
582 bail!(JsonErrorKind::UnexpectedCharacter(c as char));
583 }
584 },
585 b']' => {
586 pos += 1;
587 match why {
588 WhyComma::Array => {
589 // we finished the array, neat
590 if frame_count > 1 {
591 wip = wip.pop().unwrap();
592 }
593 }
594 _ => {
595 bail!(JsonErrorKind::UnexpectedCharacter(c as char));
596 }
597 }
598 }
599 _ => {
600 bail!(JsonErrorKind::UnexpectedCharacter(c as char));
601 }
602 },
603 },
604 }
605
606 if let Some(why) = finished_value {
607 trace!("Just finished value because of {:?}", why.green());
608 match why {
609 WhyValue::TopLevel => {}
610 WhyValue::ObjectKey => {}
611 WhyValue::ObjectValue | WhyValue::ArrayElement => {
612 if frame_count == 1 {
613 return Ok(wip.build().unwrap());
614 } else {
615 wip = wip.pop().unwrap();
616 }
617 }
618 }
619 }
620 }
621}
622
623fn skip_over_value(pos: &mut usize, input: &[u8]) -> Result<(), JsonErrorKind> {
624 let bytes = input;
625
626 // Helper for skipping whitespace
627 let skip_whitespace = |pos: &mut usize| {
628 while *pos < bytes.len() {
629 match bytes[*pos] {
630 b' ' | b'\t' | b'\n' | b'\r' => *pos += 1,
631 _ => break,
632 }
633 }
634 };
635
636 skip_whitespace(pos);
637
638 if *pos >= bytes.len() {
639 return Err(JsonErrorKind::UnexpectedEof(
640 "while skipping over value: input ended unexpectedly at root",
641 ));
642 }
643
644 match bytes[*pos] {
645 b'{' => {
646 // Skip a full object, recursively
647 *pos += 1;
648 skip_whitespace(pos);
649 if *pos < bytes.len() && bytes[*pos] == b'}' {
650 *pos += 1;
651 return Ok(());
652 }
653 loop {
654 // Skip key
655 skip_over_value(pos, input)?;
656 skip_whitespace(pos);
657 // Expect colon between key and value
658 if *pos >= bytes.len() || bytes[*pos] != b':' {
659 return Err(JsonErrorKind::UnexpectedEof(
660 "while skipping over value: object key with no colon or input ended",
661 ));
662 }
663 *pos += 1;
664 skip_whitespace(pos);
665 // Skip value
666 skip_over_value(pos, input)?;
667 skip_whitespace(pos);
668 if *pos >= bytes.len() {
669 return Err(JsonErrorKind::UnexpectedEof(
670 "while skipping over value: object value with EOF after",
671 ));
672 }
673 if bytes[*pos] == b'}' {
674 *pos += 1;
675 break;
676 } else if bytes[*pos] == b',' {
677 *pos += 1;
678 skip_whitespace(pos);
679 continue;
680 } else {
681 return Err(JsonErrorKind::UnexpectedCharacter(bytes[*pos] as char));
682 }
683 }
684 }
685 b'[' => {
686 // Skip a full array, recursively
687 *pos += 1;
688 skip_whitespace(pos);
689 if *pos < bytes.len() && bytes[*pos] == b']' {
690 *pos += 1;
691 return Ok(());
692 }
693 loop {
694 skip_over_value(pos, input)?;
695 skip_whitespace(pos);
696 if *pos >= bytes.len() {
697 return Err(JsonErrorKind::UnexpectedEof(
698 "while skipping over value: EOF inside array",
699 ));
700 }
701 if bytes[*pos] == b']' {
702 *pos += 1;
703 break;
704 } else if bytes[*pos] == b',' {
705 *pos += 1;
706 skip_whitespace(pos);
707 continue;
708 } else {
709 return Err(JsonErrorKind::UnexpectedCharacter(bytes[*pos] as char));
710 }
711 }
712 }
713 b'"' => {
714 // Skip a string, with escape processing
715 *pos += 1;
716 while *pos < bytes.len() {
717 match bytes[*pos] {
718 b'\\' => {
719 // Could have EOF after backslash
720 if *pos + 1 >= bytes.len() {
721 return Err(JsonErrorKind::UnexpectedEof(
722 "while skipping over value: EOF after backslash in string",
723 ));
724 }
725 *pos += 2; // Skip backslash and the next character (escaped)
726 }
727 b'"' => {
728 *pos += 1;
729 break;
730 }
731 _ => {
732 *pos += 1;
733 }
734 }
735 }
736 if *pos > bytes.len() {
737 return Err(JsonErrorKind::UnexpectedEof(
738 "while skipping over value: string ended unexpectedly",
739 ));
740 }
741 }
742 b't' => {
743 // Expect "true"
744 if bytes.len() >= *pos + 4 && &bytes[*pos..*pos + 4] == b"true" {
745 *pos += 4;
746 } else {
747 return Err(JsonErrorKind::UnexpectedCharacter('t'));
748 }
749 }
750 b'f' => {
751 // Expect "false"
752 if bytes.len() >= *pos + 5 && &bytes[*pos..*pos + 5] == b"false" {
753 *pos += 5;
754 } else {
755 return Err(JsonErrorKind::UnexpectedCharacter('f'));
756 }
757 }
758 b'n' => {
759 // Expect "null"
760 if bytes.len() >= *pos + 4 && &bytes[*pos..*pos + 4] == b"null" {
761 *pos += 4;
762 } else {
763 return Err(JsonErrorKind::UnexpectedCharacter('n'));
764 }
765 }
766 b'-' | b'0'..=b'9' => {
767 // Skip a number: -?\d+(\.\d+)?([eE][+-]?\d+)?
768 let start = *pos;
769 if bytes[*pos] == b'-' {
770 *pos += 1;
771 }
772 if *pos < bytes.len() && bytes[*pos] == b'0' {
773 *pos += 1;
774 } else {
775 while *pos < bytes.len() && (bytes[*pos] as char).is_ascii_digit() {
776 *pos += 1;
777 }
778 }
779 if *pos < bytes.len() && bytes[*pos] == b'.' {
780 *pos += 1;
781 let mut has_digit = false;
782 while *pos < bytes.len() && (bytes[*pos] as char).is_ascii_digit() {
783 *pos += 1;
784 has_digit = true;
785 }
786 if !has_digit {
787 return Err(JsonErrorKind::UnexpectedCharacter('.'));
788 }
789 }
790 if *pos < bytes.len() && (bytes[*pos] == b'e' || bytes[*pos] == b'E') {
791 *pos += 1;
792 if *pos < bytes.len() && (bytes[*pos] == b'+' || bytes[*pos] == b'-') {
793 *pos += 1;
794 }
795 let mut has_digit = false;
796 while *pos < bytes.len() && (bytes[*pos] as char).is_ascii_digit() {
797 *pos += 1;
798 has_digit = true;
799 }
800 if !has_digit {
801 return Err(JsonErrorKind::UnexpectedCharacter('e'));
802 }
803 }
804 if *pos == start {
805 return Err(JsonErrorKind::UnexpectedCharacter(bytes[start] as char));
806 }
807 }
808 _ => {
809 return Err(JsonErrorKind::UnexpectedCharacter(bytes[*pos] as char));
810 }
811 }
812 Ok(())
813}