1 use std
::collections
::HashMap
;
4 use winnow
::prelude
::*;
8 combinator
::{cut_err, rest}
,
9 combinator
::{delimited, preceded, separated_pair, terminated}
,
10 combinator
::{fold_repeat, separated}
,
11 error
::{AddContext, ParserError}
,
13 token
::{any, none_of, take, take_while}
,
16 use crate::json
::JsonValue
;
18 pub type Stream
<'i
> = Partial
<&'i
str>;
20 /// The root element of a JSON parser is any value
22 /// A parser has the following signature:
23 /// `&mut Stream -> PResult<Output, InputError>`, with `PResult` defined as:
24 /// `type PResult<O, E = ErrorKind> = Result<O, ErrMode<E>>;`
26 /// most of the times you can ignore the error type and use the default (but this
27 /// examples shows custom error types later on!)
29 /// Here we use `&str` as input type, but parsers can be generic over
30 /// the input type, work directly with `&[u8]`, or any other type that
31 /// implements the required traits.
32 pub fn json
<'i
, E
: ParserError
<Stream
<'i
>> + AddContext
<Stream
<'i
>, &'
static str>>(
33 input
: &mut Stream
<'i
>,
34 ) -> PResult
<JsonValue
, E
> {
35 delimited(ws
, json_value
, ws_or_eof
).parse_next(input
)
38 /// `alt` is a combinator that tries multiple parsers one by one, until
39 /// one of them succeeds
40 fn json_value
<'i
, E
: ParserError
<Stream
<'i
>> + AddContext
<Stream
<'i
>, &'
static str>>(
41 input
: &mut Stream
<'i
>,
42 ) -> PResult
<JsonValue
, E
> {
43 // `alt` combines the each value parser. It returns the result of the first
44 // successful parser, or an error
46 null
.value(JsonValue
::Null
),
47 boolean
.map(JsonValue
::Boolean
),
48 string
.map(JsonValue
::Str
),
49 float
.map(JsonValue
::Num
),
50 array
.map(JsonValue
::Array
),
51 object
.map(JsonValue
::Object
),
56 /// `tag(string)` generates a parser that recognizes the argument string.
58 /// This also shows returning a sub-slice of the original input
59 fn null
<'i
, E
: ParserError
<Stream
<'i
>>>(input
: &mut Stream
<'i
>) -> PResult
<&'i
str, E
> {
60 // This is a parser that returns `"null"` if it sees the string "null", and
62 "null".parse_next(input
)
65 /// We can combine `tag` with other functions, like `value` which returns a given constant value on
67 fn boolean
<'i
, E
: ParserError
<Stream
<'i
>>>(input
: &mut Stream
<'i
>) -> PResult
<bool
, E
> {
68 // This is a parser that returns `true` if it sees the string "true", and
70 let parse_true
= "true".value(true);
72 // This is a parser that returns `false` if it sees the string "false", and
74 let parse_false
= "false".value(false);
76 alt((parse_true
, parse_false
)).parse_next(input
)
79 /// This parser gathers all `char`s up into a `String`with a parse to recognize the double quote
80 /// character, before the string (using `preceded`) and after the string (using `terminated`).
81 fn string
<'i
, E
: ParserError
<Stream
<'i
>> + AddContext
<Stream
<'i
>, &'
static str>>(
82 input
: &mut Stream
<'i
>,
83 ) -> PResult
<String
, E
> {
86 // `cut_err` transforms an `ErrMode::Backtrack(e)` to `ErrMode::Cut(e)`, signaling to
87 // combinators like `alt` that they should not try other parsers. We were in the
88 // right branch (since we found the `"` character) but encountered an error when
91 fold_repeat(0.., character
, String
::new
, |mut string
, c
| {
98 // `context` lets you add a static string to errors to provide more information in the
99 // error chain (to indicate which parser had an error)
104 /// You can mix the above declarative parsing with an imperative style to handle more unique cases,
106 fn character
<'i
, E
: ParserError
<Stream
<'i
>>>(input
: &mut Stream
<'i
>) -> PResult
<char, E
> {
107 let c
= none_of('
\"'
).parse_next(input
)?
;
112 '
"' | '\\' | '/' => c,
121 preceded('u', unicode_escape),
129 fn unicode_escape<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<char, E> {
133 .verify(|cp| !(0xD800..0xE000).contains(cp))
134 .map(|cp| cp as u32),
135 // See https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF for details
136 separated_pair(u16_hex, "\\u
", u16_hex)
137 .verify(|(high, low)| (0xD800..0xDC00).contains(high) && (0xDC00..0xE000).contains(low))
139 let high_ten = (high as u32) - 0xD800;
140 let low_ten = (low as u32) - 0xDC00;
141 (high_ten << 10) + low_ten + 0x10000
145 // Could be probably replaced with .unwrap() or _unchecked due to the verify checks
151 fn u16_hex<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<u16, E> {
153 .verify_map(|s| u16::from_str_radix(s, 16).ok())
157 /// Some combinators, like `separated` or `repeat`, will call a parser repeatedly,
158 /// accumulating results in a `Vec`, until it encounters an error.
159 /// If you want more control on the parser application, check out the `iterator`
160 /// combinator (cf `examples/iterator.rs`)
161 fn array<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
162 input: &mut Stream<'i>,
163 ) -> PResult<Vec<JsonValue>, E> {
167 separated(0.., json_value, (ws, ',', ws)),
175 fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
176 input: &mut Stream<'i>,
177 ) -> PResult<HashMap<String, JsonValue>, E> {
181 separated(0.., key_value, (ws, ',', ws)),
189 fn key_value<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>(
190 input: &mut Stream<'i>,
191 ) -> PResult<(String, JsonValue), E> {
192 separated_pair(string, cut_err((ws, ':', ws)), json_value).parse_next(input)
195 /// Parser combinators are constructed from the bottom up:
196 /// first we write parsers for the smallest elements (here a space character),
197 /// then we'll combine them in larger parsers
198 fn ws<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
199 // Combinators like `take_while` return a function. That function is the
200 // parser,to which we can pass the input
201 take_while(0.., WS).parse_next(input)
204 fn ws_or_eof<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<&'i str, E> {
205 rest.verify(|s: &str| s.chars().all(|c| WS.contains(&c)))
209 const WS: &[char] = &[' ', '\t', '\r', '\n'];
213 #[allow(clippy::useless_attribute)]
214 #[allow(dead_code)] // its dead for benches
217 #[allow(clippy::useless_attribute)]
218 #[allow(dead_code)] // its dead for benches
219 type Error<'i> = winnow::error::InputError<Partial<&'i str>>;
224 string::<Error<'_>>.parse_peek(Partial::new("\"\"")),
225 Ok((Partial::new(""), "".to_string()))
228 string::<Error<'_>>.parse_peek(Partial::new("\"abc
\"")),
229 Ok((Partial::new(""), "abc
".to_string()))
232 string::<Error<'_>>.parse_peek(Partial::new(
233 "\"abc
\\\"\\\\\\/\\b
\\f
\\n
\\r
\\t
\\u0001
\\u2014
\u{2014}def
\""
237 "abc
\"\\/\x08
\x0C
\n\r\t\x01ββdef
".to_string()
241 string::<Error<'_>>.parse_peek(Partial::new("\"\\uD83D
\\uDE10
\"")),
242 Ok((Partial::new(""), "π
".to_string()))
245 assert!(string::<Error<'_>>.parse_peek(Partial::new("\"")).is_err());
246 assert!(string::<Error<'_>>
247 .parse_peek(Partial::new("\"abc
"))
249 assert!(string::<Error<'_>>
250 .parse_peek(Partial::new("\"\\\""))
252 assert!(string::<Error<'_>>
253 .parse_peek(Partial::new("\"\\u123
\""))
255 assert!(string::<Error<'_>>
256 .parse_peek(Partial::new("\"\\uD800
\""))
258 assert!(string::<Error<'_>>
259 .parse_peek(Partial::new("\"\\uD800
\\uD800
\""))
261 assert!(string::<Error<'_>>
262 .parse_peek(Partial::new("\"\\uDC00
\""))
268 use JsonValue::{Num, Object, Str};
270 let input = r#"{"a":42,"b":"x"}
"#;
272 let expected = Object(
274 ("a
".to_string(), Num(42.0)),
275 ("b
".to_string(), Str("x
".to_string())),
282 json::<Error<'_>>.parse_peek(Partial::new(input)),
283 Ok((Partial::new(""), expected))
289 use JsonValue::{Array, Num, Str};
291 let input = r#"[42,"x"]"#;
293 let expected = Array(vec![Num(42.0), Str("x
".to_string())]);
296 json::<Error<'_>>.parse_peek(Partial::new(input)),
297 Ok((Partial::new(""), expected))
302 fn json_whitespace() {
303 use JsonValue::{Array, Boolean, Null, Num, Object, Str};
311 "string" : " abc 123 " ,
312 "array" : [ false , 1 , "two" ] ,
313 "object" : { "a" : 1.0 , "b" : "c" }
,
314 "empty_array" : [ ] ,
320 json::<Error<'_>>.parse_peek(Partial::new(input)),
325 ("null
".to_string(), Null),
326 ("true".to_string(), Boolean(true)),
327 ("false".to_string(), Boolean(false)),
328 ("number
".to_string(), Num(123e4)),
329 ("string
".to_string(), Str(" abc
123 ".to_string())),
332 Array(vec![Boolean(false), Num(1.0), Str("two
".to_string())])
335 "object
".to_string(),
338 ("a
".to_string(), Num(1.0)),
339 ("b
".to_string(), Str("c
".to_string())),
345 ("empty_array
".to_string(), Array(vec![]),),
346 ("empty_object
".to_string(), Object(HashMap::new()),),