facet_json/
deserialize.rs

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