Skip to main content

corvus_json_schema/
document.rs

1//! A parsed JSON document that the evaluator reads in place: JSON text parsed once into one flat array of nodes, with
2//! strings borrowed from the text where they have no escapes. Parsing allocates a few buffers per document, not one
3//! per value as `serde_json::Value` does, so it is several times faster to build.
4//!
5//! ```
6//! let validator = corvus_json_schema::compile(&serde_json::json!({ "type": "array", "items": { "type": "integer" } }))
7//!     .unwrap();
8//! let document = corvus_json_schema::JsonDocument::parse("[1, 2, 3]").unwrap();
9//! assert!(validator.validate_instance(document.root()).unwrap());
10//! ```
11
12use std::cell::Cell;
13use std::fmt;
14
15use serde_json::{Map, Number, Value};
16
17use crate::instance::{ArrayView, Instance, Kind, ObjectView, View, str_eq};
18
19/// The deepest nesting of arrays and objects accepted: serde_json's default recursion limit admits 127 levels.
20const MAX_DEPTH: usize = 127;
21
22/// A value: its kind, flags (the number representation, or where a string's bytes are), a count (array items, object
23/// properties) or byte length (strings), and its data (a number's bits, a string's offset, the index of a
24/// container's first child). The children of an array or object are consecutive; an object's are key and value
25/// pairs.
26#[derive(Clone, Copy)]
27struct Node {
28    kind: Kind,
29    flags: u8,
30    len: u32,
31    data: u64,
32}
33
34const NUM_U64: u8 = 0;
35const NUM_I64: u8 = 1;
36const NUM_F64: u8 = 2;
37
38/// The string's bytes are in the source text.
39const STR_SOURCE: u8 = 0;
40/// The string's bytes are in the document's buffer of unescaped strings.
41const STR_TEXT: u8 = 1;
42
43impl Node {
44    #[inline(always)]
45    const fn new(kind: Kind, flags: u8, len: u32, data: u64) -> Node {
46        Node { kind, flags, len, data }
47    }
48}
49
50/// JSON text parsed for evaluation. It borrows the text, for the strings that need no unescaping.
51pub struct JsonDocument<'s> {
52    source: &'s str,
53    nodes: Box<[Node]>,
54    root: Node,
55    /// The unescaped strings.
56    text: Box<str>,
57}
58
59/// The text is not valid JSON, or nests arrays and objects too deeply.
60#[derive(Clone, Debug, PartialEq, Eq)]
61pub struct JsonParseError {
62    offset: usize,
63    message: &'static str,
64}
65
66impl JsonParseError {
67    /// The byte offset in the text at which the error was found.
68    pub fn offset(&self) -> usize {
69        self.offset
70    }
71
72    /// What is wrong.
73    pub fn message(&self) -> &str {
74        self.message
75    }
76}
77
78impl fmt::Display for JsonParseError {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        write!(f, "{} at byte {}", self.message, self.offset)
81    }
82}
83
84impl std::error::Error for JsonParseError {}
85
86impl<'s> JsonDocument<'s> {
87    /// Parses JSON text. As serde_json does, it rejects lone surrogates in `\u` escapes, numbers out of the range of a
88    /// double, nesting deeper than 128 and anything but whitespace after the value; of duplicate property names, the
89    /// last value is kept, at the position of the first.
90    pub fn parse(source: &'s str) -> Result<JsonDocument<'s>, JsonParseError> {
91        let mut parser = Parser::new(source, BUFFERS.take().unwrap_or_default());
92        let root = parser.parse();
93        // One allocation for the document's nodes, exactly sized.
94        let document = root.map(|root| JsonDocument {
95            source,
96            nodes: parser.nodes.as_slice().into(),
97            root,
98            text: parser.text.as_str().into(),
99        });
100        let Parser { mut nodes, mut scratch, mut frames, mut text, .. } = parser;
101        if nodes.capacity() <= MAX_KEPT_NODES && text.capacity() <= MAX_KEPT_TEXT {
102            nodes.clear();
103            scratch.clear();
104            frames.clear();
105            text.clear();
106            BUFFERS.set(Some(Buffers { nodes, scratch, frames, text }));
107        }
108        document
109    }
110
111    /// The root value.
112    #[inline]
113    pub fn root(&self) -> JsonDocumentValue<'_> {
114        JsonDocumentValue { doc: self.erase(), node: &self.root }
115    }
116
117    /// The document as a `serde_json::Value`.
118    pub fn to_value(&self) -> Value {
119        self.root().to_value()
120    }
121
122    /// The document with its source lifetime shortened to the borrow (`JsonDocument` is covariant in it).
123    #[inline(always)]
124    fn erase<'d>(&'d self) -> &'d JsonDocument<'d> {
125        self
126    }
127
128    #[inline(always)]
129    fn str_of(&self, n: &Node) -> &str {
130        let (offset, len) = (n.data as usize, n.len as usize);
131        let buffer = if n.flags == STR_TEXT { &*self.text } else { self.source };
132        debug_assert!(buffer.is_char_boundary(offset) && buffer.is_char_boundary(offset + len));
133        // SAFETY: the parser records string nodes at character boundaries within their buffer.
134        unsafe { buffer.get_unchecked(offset..offset + len) }
135    }
136
137    #[inline(always)]
138    fn children(&self, n: &Node, count: usize) -> &[Node] {
139        let start = n.data as usize;
140        debug_assert!(start + count <= self.nodes.len());
141        // SAFETY: the parser records a container's children as a range within `nodes`.
142        unsafe { self.nodes.get_unchecked(start..start + count) }
143    }
144
145    /// An object's key and value nodes, as pairs (iterating pairs, not two-node chunks, needs no per-step checks).
146    #[inline(always)]
147    fn pairs(&self, n: &Node) -> &[[Node; 2]] {
148        let items = self.children(n, 2 * n.len as usize);
149        // SAFETY: `[Node; 2]` has the layout of two consecutive `Node`s, and `items` holds exactly `n.len` pairs.
150        unsafe { std::slice::from_raw_parts(items.as_ptr().cast::<[Node; 2]>(), n.len as usize) }
151    }
152}
153
154impl fmt::Debug for JsonDocument<'_> {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        f.debug_struct("JsonDocument").field("nodes", &self.nodes.len()).finish()
157    }
158}
159
160/// A value in a [`JsonDocument`]: an [`Instance`] for [`crate::Validator::validate_instance`].
161#[derive(Clone, Copy)]
162pub struct JsonDocumentValue<'d> {
163    doc: &'d JsonDocument<'d>,
164    node: &'d Node,
165}
166
167/// The items of an array in a [`JsonDocument`].
168#[derive(Clone, Copy)]
169pub struct JsonDocumentArray<'d> {
170    doc: &'d JsonDocument<'d>,
171    items: &'d [Node],
172}
173
174/// The properties of an object in a [`JsonDocument`].
175#[derive(Clone, Copy)]
176pub struct JsonDocumentObject<'d> {
177    doc: &'d JsonDocument<'d>,
178    /// Key and value nodes.
179    pairs: &'d [[Node; 2]],
180}
181
182impl<'d> JsonDocumentValue<'d> {
183    #[inline(always)]
184    fn number(n: &Node) -> Number {
185        match n.flags {
186            NUM_U64 => Number::from(n.data),
187            NUM_I64 => Number::from(n.data as i64),
188            // The parser only records finite doubles.
189            _ => Number::from_f64(f64::from_bits(n.data)).unwrap_or_else(|| Number::from(0)),
190        }
191    }
192
193    /// The value as a `serde_json::Value`.
194    pub fn to_value(self) -> Value {
195        match self.view() {
196            View::Null => Value::Null,
197            View::Bool(b) => Value::Bool(b),
198            View::Number(n) => Value::Number(n),
199            View::String(s) => Value::String(s.to_owned()),
200            View::Array(a) => Value::Array(a.iter().map(JsonDocumentValue::to_value).collect()),
201            View::Object(o) => {
202                let mut map = Map::with_capacity(o.len());
203                for (k, v) in o.iter() {
204                    map.insert(k.to_owned(), v.to_value());
205                }
206                Value::Object(map)
207            }
208        }
209    }
210}
211
212impl<'d> Instance<'d> for JsonDocumentValue<'d> {
213    type Array = JsonDocumentArray<'d>;
214    type Object = JsonDocumentObject<'d>;
215
216    #[inline(always)]
217    fn view(self) -> View<'d, Self> {
218        let (doc, n) = (self.doc, self.node);
219        match n.kind {
220            Kind::Null => View::Null,
221            Kind::Bool => View::Bool(n.data != 0),
222            Kind::Number => View::Number(Self::number(n)),
223            Kind::String => View::String(doc.str_of(n)),
224            Kind::Array => View::Array(JsonDocumentArray { doc, items: doc.children(n, n.len as usize) }),
225            Kind::Object => View::Object(JsonDocumentObject { doc, pairs: doc.pairs(n) }),
226        }
227    }
228
229    #[inline(always)]
230    fn kind(self) -> Kind {
231        self.node.kind
232    }
233}
234
235impl<'d> ArrayView<'d> for JsonDocumentArray<'d> {
236    type Item = JsonDocumentValue<'d>;
237
238    #[inline(always)]
239    fn len(self) -> usize {
240        self.items.len()
241    }
242
243    #[inline(always)]
244    fn get(self, index: usize) -> JsonDocumentValue<'d> {
245        JsonDocumentValue { doc: self.doc, node: &self.items[index] }
246    }
247
248    #[inline(always)]
249    fn iter(self) -> impl Iterator<Item = JsonDocumentValue<'d>> {
250        let doc = self.doc;
251        self.items.iter().map(move |node| JsonDocumentValue { doc, node })
252    }
253
254    #[inline(always)]
255    fn tail(self, start: usize) -> impl Iterator<Item = JsonDocumentValue<'d>> {
256        let doc = self.doc;
257        self.items.get(start..).unwrap_or_default().iter().map(move |node| JsonDocumentValue { doc, node })
258    }
259}
260
261impl<'d> ObjectView<'d> for JsonDocumentObject<'d> {
262    type Item = JsonDocumentValue<'d>;
263
264    #[inline(always)]
265    fn len(self) -> usize {
266        self.pairs.len()
267    }
268
269    #[inline]
270    fn get(self, name: &str) -> Option<JsonDocumentValue<'d>> {
271        let doc = self.doc;
272        self.pairs.iter().find(|[k, _]| str_eq(doc.str_of(k), name)).map(|[_, v]| JsonDocumentValue { doc, node: v })
273    }
274
275    #[inline]
276    fn contains_key(self, name: &str) -> bool {
277        let doc = self.doc;
278        self.pairs.iter().any(|[k, _]| str_eq(doc.str_of(k), name))
279    }
280
281    #[inline(always)]
282    fn iter(self) -> impl Iterator<Item = (&'d str, JsonDocumentValue<'d>)> {
283        let doc = self.doc;
284        self.pairs.iter().map(move |[k, v]| (doc.str_of(k), JsonDocumentValue { doc, node: v }))
285    }
286
287    #[inline(always)]
288    fn values(self) -> impl Iterator<Item = JsonDocumentValue<'d>> {
289        let doc = self.doc;
290        self.pairs.iter().map(move |[_, v]| JsonDocumentValue { doc, node: v })
291    }
292}
293
294/// The parser's working buffers, kept between parses on a thread so that a document costs one allocation (two when
295/// strings need unescaping): an allocator's cost per call, which musl's makes high, otherwise dominates small
296/// documents.
297#[derive(Default)]
298struct Buffers {
299    nodes: Vec<Node>,
300    scratch: Vec<Node>,
301    frames: Vec<Frame>,
302    text: String,
303}
304
305thread_local! {
306    /// Taken for the length of a parse, so a parse that a parse somehow re-entered would start with new buffers.
307    static BUFFERS: Cell<Option<Buffers>> = const { Cell::new(None) };
308}
309
310/// Buffers that grew beyond this many nodes (16 MiB) for a large document are released, not kept.
311const MAX_KEPT_NODES: usize = 1 << 20;
312/// Nor is an unescaped-string buffer beyond 16 MiB.
313const MAX_KEPT_TEXT: usize = 1 << 24;
314
315/// An open array or object: where its children start in the scratch stack.
316#[derive(Clone, Copy)]
317struct Frame {
318    start: u32,
319    object: bool,
320}
321
322struct Parser<'s> {
323    source: &'s str,
324    b: &'s [u8],
325    i: usize,
326    /// Finished children of closed containers, each container's consecutive.
327    nodes: Vec<Node>,
328    /// The values of the open containers, innermost last; a container's run moves to `nodes` when it closes.
329    scratch: Vec<Node>,
330    frames: Vec<Frame>,
331    text: String,
332}
333
334/// Bytes equal to `n` in a word (exact at the lowest set bit, which is all the scanner uses).
335#[inline(always)]
336const fn eq_bytes(w: u64, n: u8) -> u64 {
337    let x = w ^ (0x0101_0101_0101_0101 * n as u64);
338    x.wrapping_sub(0x0101_0101_0101_0101) & !x & 0x8080_8080_8080_8080
339}
340
341/// Bytes below 0x20 in a word (exact at the lowest set bit).
342#[inline(always)]
343const fn control_bytes(w: u64) -> u64 {
344    w.wrapping_sub(0x2020_2020_2020_2020) & !w & 0x8080_8080_8080_8080
345}
346
347impl<'s> Parser<'s> {
348    fn new(source: &'s str, buffers: Buffers) -> Parser<'s> {
349        Parser {
350            source,
351            b: source.as_bytes(),
352            i: 0,
353            nodes: buffers.nodes,
354            scratch: buffers.scratch,
355            frames: buffers.frames,
356            text: buffers.text,
357        }
358    }
359
360    #[cold]
361    fn error<T>(&self, message: &'static str) -> Result<T, JsonParseError> {
362        Err(JsonParseError { offset: self.i, message })
363    }
364
365    #[inline(always)]
366    fn skip_ws(&mut self) {
367        while let Some(&c) = self.b.get(self.i) {
368            if !matches!(c, b' ' | b'\n' | b'\r' | b'\t') {
369                break;
370            }
371            self.i += 1;
372        }
373    }
374
375    #[inline(always)]
376    fn peek(&self) -> Option<u8> {
377        self.b.get(self.i).copied()
378    }
379
380    /// Parses the text into `nodes`, returning the root.
381    fn parse(&mut self) -> Result<Node, JsonParseError> {
382        if self.source.len() > u32::MAX as usize {
383            return self.error("document too large");
384        }
385        self.skip_ws();
386        'value: loop {
387            // A value.
388            match self.peek() {
389                Some(b'{') => {
390                    self.i += 1;
391                    self.skip_ws();
392                    if self.peek() == Some(b'}') {
393                        self.i += 1;
394                        self.check_depth()?;
395                        self.scratch.push(Node::new(Kind::Object, 0, 0, 0));
396                    } else {
397                        self.open(true)?;
398                        self.key()?;
399                        continue 'value;
400                    }
401                }
402                Some(b'[') => {
403                    self.i += 1;
404                    self.skip_ws();
405                    if self.peek() == Some(b']') {
406                        self.i += 1;
407                        self.check_depth()?;
408                        self.scratch.push(Node::new(Kind::Array, 0, 0, 0));
409                    } else {
410                        self.open(false)?;
411                        continue 'value;
412                    }
413                }
414                Some(b'"') => {
415                    let n = self.string()?;
416                    self.scratch.push(n);
417                }
418                Some(b't') => self.literal(b"true", Node::new(Kind::Bool, 0, 0, 1))?,
419                Some(b'f') => self.literal(b"false", Node::new(Kind::Bool, 0, 0, 0))?,
420                Some(b'n') => self.literal(b"null", Node::new(Kind::Null, 0, 0, 0))?,
421                Some(b'-' | b'0'..=b'9') => {
422                    let n = self.number()?;
423                    self.scratch.push(n);
424                }
425                Some(_) => return self.error("expected a value"),
426                None => return self.error("unexpected end of input"),
427            }
428            // After a value: separators and closing brackets, until the next value or the end.
429            loop {
430                let Some(&frame) = self.frames.last() else {
431                    self.skip_ws();
432                    if self.i != self.b.len() {
433                        return self.error("trailing characters");
434                    }
435                    return Ok(self.scratch[0]);
436                };
437                self.skip_ws();
438                match self.peek() {
439                    Some(b',') => {
440                        self.i += 1;
441                        self.skip_ws();
442                        if frame.object {
443                            self.key()?;
444                        }
445                        continue 'value;
446                    }
447                    Some(b'}') if frame.object => {
448                        self.i += 1;
449                        self.close(frame);
450                    }
451                    Some(b']') if !frame.object => {
452                        self.i += 1;
453                        self.close(frame);
454                    }
455                    Some(_) => {
456                        return self.error(if frame.object { "expected ',' or '}'" } else { "expected ',' or ']'" });
457                    }
458                    None => return self.error("unexpected end of input"),
459                }
460            }
461        }
462    }
463
464    #[inline(always)]
465    fn open(&mut self, object: bool) -> Result<(), JsonParseError> {
466        self.check_depth()?;
467        self.frames.push(Frame { start: self.scratch.len() as u32, object });
468        Ok(())
469    }
470
471    /// An array or object may open at the current depth (an empty one counts, as in serde_json).
472    #[inline(always)]
473    fn check_depth(&self) -> Result<(), JsonParseError> {
474        if self.frames.len() >= MAX_DEPTH { self.error("recursion limit exceeded") } else { Ok(()) }
475    }
476
477    /// A property name and its colon, leaving the parser at the value.
478    #[inline(always)]
479    fn key(&mut self) -> Result<(), JsonParseError> {
480        if self.peek() != Some(b'"') {
481            return self.error("expected a property name");
482        }
483        let k = self.string()?;
484        self.scratch.push(k);
485        self.skip_ws();
486        if self.peek() != Some(b':') {
487            return self.error("expected ':'");
488        }
489        self.i += 1;
490        self.skip_ws();
491        Ok(())
492    }
493
494    /// Moves the closed container's children to `nodes` and pushes the container in their place.
495    #[inline(always)]
496    fn close(&mut self, frame: Frame) {
497        self.frames.pop();
498        let start = frame.start as usize;
499        if frame.object && self.scratch.len() - start > 2 {
500            self.dedupe(start);
501        }
502        let first = self.nodes.len() as u64;
503        let children = self.scratch.len() - start;
504        self.nodes.extend_from_slice(&self.scratch[start..]);
505        self.scratch.truncate(start);
506        let (kind, count) = if frame.object { (Kind::Object, children / 2) } else { (Kind::Array, children) };
507        self.scratch.push(Node::new(kind, 0, count as u32, first));
508    }
509
510    fn key_str(&self, n: &Node) -> &str {
511        let (offset, len) = (n.data as usize, n.len as usize);
512        if n.flags == STR_TEXT { &self.text[offset..offset + len] } else { &self.source[offset..offset + len] }
513    }
514
515    /// Of duplicate property names in the object whose pairs start at `start`, keeps the last value at the first
516    /// position (as `serde_json::Map` with `preserve_order` does).
517    fn dedupe(&mut self, start: usize) {
518        let pairs = &self.scratch[start..];
519        let count = pairs.len() / 2;
520        let duplicate = if count <= 16 {
521            (1..count).any(|j| (0..j).any(|i| str_eq(self.key_str(&pairs[2 * i]), self.key_str(&pairs[2 * j]))))
522        } else {
523            let mut seen = std::collections::HashSet::with_capacity(count);
524            (0..count).any(|j| !seen.insert(self.key_str(&pairs[2 * j])))
525        };
526        if !duplicate {
527            return;
528        }
529        let mut kept: Vec<Node> = Vec::with_capacity(pairs.len());
530        for p in pairs.chunks_exact(2) {
531            let name = self.key_str(&p[0]);
532            match kept.chunks_exact(2).position(|q| self.key_str(&q[0]) == name) {
533                Some(at) => kept[2 * at + 1] = p[1],
534                None => kept.extend_from_slice(p),
535            }
536        }
537        self.scratch.truncate(start);
538        self.scratch.extend_from_slice(&kept);
539    }
540
541    #[inline(always)]
542    fn literal(&mut self, word: &[u8], node: Node) -> Result<(), JsonParseError> {
543        if self.b.get(self.i..self.i + word.len()) != Some(word) {
544            return self.error("expected a value");
545        }
546        self.i += word.len();
547        self.scratch.push(node);
548        Ok(())
549    }
550
551    /// A string, from its opening quote.
552    #[inline(always)]
553    fn string(&mut self) -> Result<Node, JsonParseError> {
554        let start = self.i + 1;
555        let mut j = start;
556        let b = self.b;
557        // Eight bytes at a time to the first quote, backslash or control character.
558        while j + 8 <= b.len() {
559            let w = u64::from_le_bytes(b[j..j + 8].try_into().unwrap());
560            let special = eq_bytes(w, b'"') | eq_bytes(w, b'\\') | control_bytes(w);
561            if special != 0 {
562                j += (special.trailing_zeros() / 8) as usize;
563                return self.string_at(start, j);
564            }
565            j += 8;
566        }
567        while j < b.len() && !matches!(b[j], b'"' | b'\\' | 0..0x20) {
568            j += 1;
569        }
570        self.string_at(start, j)
571    }
572
573    #[inline(always)]
574    fn string_at(&mut self, start: usize, j: usize) -> Result<Node, JsonParseError> {
575        match self.b.get(j) {
576            Some(b'"') => {
577                self.i = j + 1;
578                Ok(Node::new(Kind::String, STR_SOURCE, (j - start) as u32, start as u64))
579            }
580            Some(b'\\') => self.escaped(start, j),
581            Some(_) => {
582                self.i = j;
583                self.error("control character in a string")
584            }
585            None => {
586                self.i = j;
587                self.error("unterminated string")
588            }
589        }
590    }
591
592    /// The rest of a string with escapes, unescaped into the text buffer: `j` is at the first backslash.
593    #[cold]
594    fn escaped(&mut self, start: usize, mut j: usize) -> Result<Node, JsonParseError> {
595        let offset = self.text.len();
596        let b = self.b;
597        let mut run = start;
598        loop {
599            match b.get(j) {
600                Some(b'"') => {
601                    self.text.push_str(&self.source[run..j]);
602                    self.i = j + 1;
603                    let len = self.text.len() - offset;
604                    return Ok(Node::new(Kind::String, STR_TEXT, len as u32, offset as u64));
605                }
606                Some(b'\\') => {
607                    self.text.push_str(&self.source[run..j]);
608                    let c = match b.get(j + 1) {
609                        Some(b'"') => '"',
610                        Some(b'\\') => '\\',
611                        Some(b'/') => '/',
612                        Some(b'b') => '\u{8}',
613                        Some(b'f') => '\u{c}',
614                        Some(b'n') => '\n',
615                        Some(b'r') => '\r',
616                        Some(b't') => '\t',
617                        Some(b'u') => {
618                            let (c, next) = self.unicode_escape(j)?;
619                            self.text.push(c);
620                            j = next;
621                            run = j;
622                            continue;
623                        }
624                        _ => {
625                            self.i = j;
626                            return self.error("invalid escape");
627                        }
628                    };
629                    self.text.push(c);
630                    j += 2;
631                    run = j;
632                }
633                Some(0..0x20) => {
634                    self.i = j;
635                    return self.error("control character in a string");
636                }
637                Some(_) => j += 1,
638                None => {
639                    self.i = j;
640                    return self.error("unterminated string");
641                }
642            }
643        }
644    }
645
646    /// A `\u` escape at `j` (and its low surrogate, for a high one): the character and the index after it.
647    fn unicode_escape(&mut self, j: usize) -> Result<(char, usize), JsonParseError> {
648        let hex = |p: &Self, at: usize| -> Option<u32> {
649            let digits = p.b.get(at..at + 4)?;
650            let mut v = 0u32;
651            for &d in digits {
652                v = v * 16 + (d as char).to_digit(16)?;
653            }
654            Some(v)
655        };
656        let Some(u) = hex(self, j + 2) else {
657            self.i = j;
658            return self.error("invalid \\u escape");
659        };
660        match u {
661            0xD800..=0xDBFF => {
662                let low = (self.b.get(j + 6) == Some(&b'\\') && self.b.get(j + 7) == Some(&b'u'))
663                    .then(|| hex(self, j + 8))
664                    .flatten();
665                match low {
666                    Some(l @ 0xDC00..=0xDFFF) => {
667                        let c = 0x10000 + ((u - 0xD800) << 10) + (l - 0xDC00);
668                        Ok((char::from_u32(c).unwrap(), j + 12))
669                    }
670                    _ => {
671                        self.i = j;
672                        self.error("lone leading surrogate in hex escape")
673                    }
674                }
675            }
676            0xDC00..=0xDFFF => {
677                self.i = j;
678                self.error("lone trailing surrogate in hex escape")
679            }
680            _ => Ok((char::from_u32(u).unwrap(), j + 6)),
681        }
682    }
683
684    /// A number: unsigned or negative integers that fit 64 bits as integers, anything else as a double (as serde_json
685    /// classifies them).
686    #[inline(always)]
687    fn number(&mut self) -> Result<Node, JsonParseError> {
688        let b = self.b;
689        let start = self.i;
690        let mut j = start;
691        let negative = b[j] == b'-';
692        if negative {
693            j += 1;
694        }
695        let mut value: u64 = 0;
696        let mut overflow = false;
697        match b.get(j) {
698            Some(b'0') => j += 1,
699            Some(b'1'..=b'9') => {
700                while let Some(&d @ b'0'..=b'9') = b.get(j) {
701                    match value.checked_mul(10).and_then(|v| v.checked_add((d - b'0') as u64)) {
702                        Some(v) => value = v,
703                        None => overflow = true,
704                    }
705                    j += 1;
706                }
707            }
708            _ => {
709                self.i = j;
710                return self.error("invalid number");
711            }
712        }
713        let mut float = false;
714        if b.get(j) == Some(&b'.') {
715            j += 1;
716            if !matches!(b.get(j), Some(b'0'..=b'9')) {
717                self.i = j;
718                return self.error("invalid number");
719            }
720            while matches!(b.get(j), Some(b'0'..=b'9')) {
721                j += 1;
722            }
723            float = true;
724        }
725        if matches!(b.get(j), Some(b'e' | b'E')) {
726            j += 1;
727            if matches!(b.get(j), Some(b'+' | b'-')) {
728                j += 1;
729            }
730            if !matches!(b.get(j), Some(b'0'..=b'9')) {
731                self.i = j;
732                return self.error("invalid number");
733            }
734            while matches!(b.get(j), Some(b'0'..=b'9')) {
735                j += 1;
736            }
737            float = true;
738        }
739        self.i = j;
740        if !float && !overflow {
741            if !negative {
742                return Ok(Node::new(Kind::Number, NUM_U64, 0, value));
743            }
744            // serde_json reads -0 as the double.
745            if value != 0 && value <= i64::MAX as u64 + 1 {
746                return Ok(Node::new(Kind::Number, NUM_I64, 0, (value as i64).wrapping_neg() as u64));
747            }
748        }
749        let f: f64 = self.source[start..j].parse().unwrap_or(f64::INFINITY);
750        if !f.is_finite() {
751            self.i = start;
752            return self.error("number out of range");
753        }
754        Ok(Node::new(Kind::Number, NUM_F64, 0, f.to_bits()))
755    }
756}
757
758#[cfg(test)]
759mod tests {
760    use super::*;
761
762    fn same(text: &str) {
763        let expected: Value = serde_json::from_str(text).unwrap();
764        let document = JsonDocument::parse(text).unwrap_or_else(|e| panic!("{text}: {e}"));
765        assert_eq!(document.to_value(), expected, "{text}");
766        // The number representations match too (serde_json's Value equality compares them).
767        assert_eq!(serde_json::to_string(&document.to_value()).unwrap(), serde_json::to_string(&expected).unwrap());
768    }
769
770    fn both_reject(text: &str) {
771        assert!(serde_json::from_str::<Value>(text).is_err(), "serde_json accepts {text}");
772        assert!(JsonDocument::parse(text).is_err(), "accepted {text}");
773    }
774
775    #[test]
776    fn values_match_serde_json() {
777        for text in [
778            "null",
779            " true ",
780            "false",
781            "0",
782            "-0",
783            "-0.0",
784            "1",
785            "-1",
786            "18446744073709551615",
787            "18446744073709551616",
788            "-9223372036854775808",
789            "-9223372036854775809",
790            "1.5",
791            "1e3",
792            "1E+3",
793            "1.0e-3",
794            "123456789012345678901234567890",
795            "2.2250738585072014e-308",
796            "\"\"",
797            "\"plain text, longer than eight bytes\"",
798            "\"caf\u{e9} \u{1f600}\"",
799            r#""esc \" \\ \/ \b \f \n \r \t é 😀 end""#,
800            r#""\u0000""#,
801            "[]",
802            "{}",
803            "[1, [2, [3, []]], {}]",
804            r#"{"a": 1, "b": [true, null], "c": {"d": "e"}}"#,
805            r#"{"a": 1, "b": 2, "a": 3}"#,
806            r#"{"x": 1, "y": 2, "x": {"z": 1}, "y": 4, "w": 5}"#,
807        ] {
808            same(text);
809        }
810        let many: String =
811            format!("{{{}}}", (0..40).map(|i| format!("\"k{}\": {i}", i % 25)).collect::<Vec<_>>().join(","));
812        same(&many);
813    }
814
815    #[test]
816    fn doubles_are_correctly_rounded() {
817        // serde_json (without float_roundtrip) reads this one ulp off.
818        let text = "-90.50242899999999";
819        let d = JsonDocument::parse(text).unwrap();
820        assert_eq!(d.to_value().as_f64().unwrap().to_bits(), text.parse::<f64>().unwrap().to_bits());
821    }
822
823    #[test]
824    fn rejects_what_serde_json_rejects() {
825        for text in [
826            "",
827            " ",
828            "nul",
829            "tru",
830            "01",
831            "-",
832            "1.",
833            ".5",
834            "1e",
835            "+1",
836            "1e400",
837            "[1,]",
838            "[1 2]",
839            "{\"a\" 1}",
840            "{\"a\": 1,}",
841            "{a: 1}",
842            "\"unterminated",
843            "\"tab\there\"",
844            r#""\x""#,
845            r#""\ud800""#,
846            r#""\udc00""#,
847            r#""\ud800A""#,
848            "[1] 2",
849            "[",
850            "{",
851        ] {
852            both_reject(text);
853        }
854    }
855
856    #[test]
857    fn depth_limit() {
858        for inner in ["", "1"] {
859            let nest = |n: usize| format!("{}{inner}{}", "[".repeat(n), "]".repeat(n));
860            assert!(JsonDocument::parse(&nest(MAX_DEPTH)).is_ok());
861            assert!(JsonDocument::parse(&nest(MAX_DEPTH + 1)).is_err());
862            assert!(serde_json::from_str::<Value>(&nest(MAX_DEPTH)).is_ok());
863            assert!(serde_json::from_str::<Value>(&nest(MAX_DEPTH + 1)).is_err());
864        }
865    }
866
867    #[test]
868    fn reads_in_place() {
869        let d = JsonDocument::parse(r#"{"a": [1, "x\n"], "b": {"c": null}}"#).unwrap();
870        let View::Object(o) = d.root().view() else { panic!() };
871        assert_eq!(o.len(), 2);
872        assert!(o.contains_key("b") && !o.contains_key("c"));
873        let View::Array(a) = o.get("a").unwrap().view() else { panic!() };
874        assert_eq!(a.len(), 2);
875        assert!(matches!(a.get(1).view(), View::String("x\n")));
876        assert_eq!(a.tail(1).count(), 1);
877        assert_eq!(a.tail(5).count(), 0);
878        assert_eq!(o.iter().map(|(k, _)| k).collect::<Vec<_>>(), ["a", "b"]);
879    }
880}