Skip to main content

json_cursor/
lib.rs

1//! Read JSON one value at a time: fast, strict, and with every number exact.
2//!
3//! A [`Cursor`] walks through a JSON document from start to end. You ask for the next key, string
4//! or number, and it hands it to you straight from your bytes, so you can build your own types
5//! with no tree in between.
6//!
7//! ```
8//! use json_cursor::Cursor;
9//!
10//! let mut cursor = Cursor::new(r#"{"name": "Ada", "born": 1815, "languages": ["English"]}"#);
11//! let mut buf = String::new(); // used only when a key or string has escapes
12//!
13//! let mut next = cursor.first_key(&mut buf)?;
14//! while let Some(key) = next {
15//!     match key {
16//!         "name" => assert_eq!(cursor.string(&mut buf)?, "Ada"),
17//!         "born" => assert_eq!(cursor.number()?.as_i64(), Some(1815)),
18//!         _ => cursor.skip()?, // anything else is checked, then passed over
19//!     }
20//!     next = cursor.next_key(&mut buf)?;
21//! }
22//! cursor.finish()?; // only whitespace may follow
23//! # Ok::<(), json_cursor::Error>(())
24//! ```
25//!
26//! - [`Cursor`] reads a document one value at a time.
27//! - [`Number`] keeps a number's text exactly, and gives its value as an `i64` or an `f64`.
28//! - [`validate`] checks a whole document in one call.
29//! - [`Error`] says what went wrong, and at which byte.
30//!
31//! The [README](https://github.com/FusionVault/json-cursor) has a guide, and the benchmarks against
32//! other parsers.
33
34#![no_std]
35
36extern crate alloc;
37
38/// Every Rust code block in the README is compiled and run as a doctest.
39#[cfg(doctest)]
40#[doc = include_str!("../README.md")]
41pub struct ReadmeDoctests;
42
43// One part of JSON in each module. `cursor` is the public API, on top of the rest.
44mod cursor; // the cursor: reads values one at a time
45mod error; // what went wrong, and at which byte
46mod number; // numbers: their grammar, their digits, their exact values
47mod scan; // the position in the input: whitespace, literals, eight bytes at a time
48mod skip; // passing over a value of any kind, checked, on a stack of its own
49mod text; // strings: plain runs, escapes, UTF-8
50
51// What the unit tests share.
52#[cfg(test)]
53mod testing;
54
55pub use cursor::{Cursor, Kind, Value, DEFAULT_DEPTH_LIMIT};
56pub use error::{Error, ErrorKind};
57pub use number::Number;
58
59/// Checks that `bytes` hold one JSON value, with nothing but whitespace around it.
60///
61/// It reads them once. Their UTF-8 is checked inside strings, and only where a string has a byte
62/// that is not ASCII: outside strings, the grammar admits ASCII alone.
63///
64/// ```
65/// assert!(json_cursor::validate(br#"{"a": [1, 2.5, "x"]}"#).is_ok());
66/// assert!(json_cursor::validate(br#"{"a": 1,}"#).is_err());
67/// ```
68pub fn validate(bytes: &[u8]) -> Result<(), Error> {
69    let mut scan = scan::Scan::new(bytes);
70    skip::skip::<true>(&mut scan, DEFAULT_DEPTH_LIMIT)?;
71    scan.finish()
72}