1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! This crate implements a queryable, streaming, JSON pull parser.
//!
//! - __Pull parser?__: The [parser](crate::TokenReader) is implemented as iterator that emits
//! [tokens](crate::Token).
//! - __Streaming?__: The JSON document being parsed is never fully loaded into memory. It is read
//! & validated byte by byte. This makes it ideal for dealing with large JSON documents
//! - __Queryable?__ You can [configure the parser](crate::TokenReader::with_mask) to only emit & allocate
//! tokens for the parts of the input you are interested in.
//!
//! JSON is expected to conform to [RFC
//! 8259](https://datatracker.ietf.org/doc/html/rfc8259).
//! However, [newline-delimited JSON](https://github.com/ndjson/ndjson-spec) and [concatenated
//! json](https://en.wikipedia.org/wiki/JSON_streaming#Concatenated_JSON) formats are also
//! [supported](crate::TokenReader::with_format).
//!
//! Input can be anything that implements the [`Read`](std::io::Read) trait (e.g. a file, byte
//! slice, network socket etc..)
//!
//! ## Basic Usage
//!
//! ```
//! use jsn::{TokenReader, mask::*, Format};
//! use std::error::Error;
//!
//! fn main() -> Result<(), Box<dyn Error>> {
//! let data = r#"
//! {
//! "name": "John Doe",
//! "age": 43,
//! "nicknames": [ "joe" ],
//! "phone": {
//! "carrier": "Verizon",
//! "numbers": [ "+44 1234567", "+44 2345678" ]
//! }
//! }
//! {
//! "name": "Jane Doe",
//! "age": 32,
//! "nicknames": [ "J" ],
//! "phone": {
//! "carrier": "AT&T",
//! "numbers": ["+33 38339"]
//! }
//! }
//! "#;
//!
//! let mask = key("numbers").and(index(0))
//! .or(key("name"))
//! .or(key("age"));
//! let mut iter = TokenReader::new(data.as_bytes())
//! .with_mask(mask)
//! .with_format(Format::Concatenated)
//! .into_iter();
//!
//! assert_eq!(iter.next().unwrap()?, "John Doe");
//! assert_eq!(iter.next().unwrap()?, 43);
//! assert_eq!(iter.next().unwrap()?, "+44 1234567");
//! assert_eq!(iter.next().unwrap()?, "Jane Doe");
//! assert_eq!(iter.next().unwrap()?, 32);
//! assert_eq!(iter.next().unwrap()?, "+33 38339");
//! assert_eq!(iter.next(), None);
//!
//! Ok(())
//! }
//! ```
//!
//! __A few things to notice and whet your appetite:__
//! - This is new-line delimited JSON
//! - We only pay for heap allocating the tokens we extracted (i.e. the first index in the
//! "numbers" array and the "name" and "age" values).
//! - You can compare tokens to native rust types
//! - Token masks match anywhere in json; Though the top-level value was an object, we used the
//! `index` mask to match a token that was at index 0 in an array nested in the "phones" object.
pub use ;
pub use ;
pub use ;
;