1 // `impl Trait` is not required for this parser but we use to to show that it can be used to
2 // significantly simplify things
3
4 #![cfg(feature = "std")]
5
6 #[macro_use]
7 extern crate criterion;
8
9 #[macro_use]
10 extern crate combine;
11
12 use std::{collections::HashMap, fs::File, io::Read, path::Path};
13
14 use {
15 combine::{
16 error::{Commit, ParseError},
17 parser::{
18 char::{char, digit, spaces, string},
19 choice::{choice, optional},
20 function::parser,
21 repeat::{many, many1, sep_by},
22 sequence::between,
23 token::{any, satisfy, satisfy_map},
24 },
25 stream::{
26 buffered,
27 position::{self, SourcePosition},
28 IteratorStream,
29 },
30 EasyParser, Parser, Stream, StreamOnce,
31 },
32 criterion::{black_box, Bencher, Criterion},
33 };
34
35 #[derive(PartialEq, Debug)]
36 enum Value {
37 Number(f64),
38 String(String),
39 Bool(bool),
40 Null,
41 Object(HashMap<String, Value>),
42 Array(Vec<Value>),
43 }
44
lex<Input, P>(p: P) -> impl Parser<Input, Output = P::Output> where P: Parser<Input>, Input: Stream<Token = char>, <Input as StreamOnce>::Error: ParseError< <Input as StreamOnce>::Token, <Input as StreamOnce>::Range, <Input as StreamOnce>::Position, >,45 fn lex<Input, P>(p: P) -> impl Parser<Input, Output = P::Output>
46 where
47 P: Parser<Input>,
48 Input: Stream<Token = char>,
49 <Input as StreamOnce>::Error: ParseError<
50 <Input as StreamOnce>::Token,
51 <Input as StreamOnce>::Range,
52 <Input as StreamOnce>::Position,
53 >,
54 {
55 p.skip(spaces())
56 }
57
integer<Input>() -> impl Parser<Input, Output = i64> where Input: Stream<Token = char>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,58 fn integer<Input>() -> impl Parser<Input, Output = i64>
59 where
60 Input: Stream<Token = char>,
61 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
62 {
63 lex(many1(digit()))
64 .map(|s: String| {
65 let mut n = 0;
66 for c in s.chars() {
67 n = n * 10 + (c as i64 - '0' as i64);
68 }
69 n
70 })
71 .expected("integer")
72 }
73
number<Input>() -> impl Parser<Input, Output = f64> where Input: Stream<Token = char>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,74 fn number<Input>() -> impl Parser<Input, Output = f64>
75 where
76 Input: Stream<Token = char>,
77 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
78 {
79 let i = char('0').map(|_| 0.0).or(integer().map(|x| x as f64));
80 let fractional = many(digit()).map(|digits: String| {
81 let mut magnitude = 1.0;
82 digits.chars().fold(0.0, |acc, d| {
83 magnitude /= 10.0;
84 match d.to_digit(10) {
85 Some(d) => acc + (d as f64) * magnitude,
86 None => panic!("Not a digit"),
87 }
88 })
89 });
90
91 let exp = satisfy(|c| c == 'e' || c == 'E').with(optional(char('-')).and(integer()));
92 lex(optional(char('-'))
93 .and(i)
94 .map(|(sign, n)| if sign.is_some() { -n } else { n })
95 .and(optional(char('.')).with(fractional))
96 .map(|(x, y)| if x >= 0.0 { x + y } else { x - y })
97 .and(optional(exp))
98 .map(|(n, exp_option)| match exp_option {
99 Some((sign, e)) => {
100 let e = if sign.is_some() { -e } else { e };
101 n * 10.0f64.powi(e as i32)
102 }
103 None => n,
104 }))
105 .expected("number")
106 }
107
json_char<Input>() -> impl Parser<Input, Output = char> where Input: Stream<Token = char>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,108 fn json_char<Input>() -> impl Parser<Input, Output = char>
109 where
110 Input: Stream<Token = char>,
111 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
112 {
113 parser(|input: &mut Input| {
114 let (c, committed) = any().parse_lazy(input).into_result()?;
115 let mut back_slash_char = satisfy_map(|c| {
116 Some(match c {
117 '"' => '"',
118 '\\' => '\\',
119 '/' => '/',
120 'b' => '\u{0008}',
121 'f' => '\u{000c}',
122 'n' => '\n',
123 'r' => '\r',
124 't' => '\t',
125 _ => return None,
126 })
127 });
128 match c {
129 '\\' => committed.combine(|_| back_slash_char.parse_stream(input).into_result()),
130 '"' => Err(Commit::Peek(Input::Error::empty(input.position()).into())),
131 _ => Ok((c, committed)),
132 }
133 })
134 }
135
json_string<Input>() -> impl Parser<Input, Output = String> where Input: Stream<Token = char>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,136 fn json_string<Input>() -> impl Parser<Input, Output = String>
137 where
138 Input: Stream<Token = char>,
139 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
140 {
141 between(char('"'), lex(char('"')), many(json_char())).expected("string")
142 }
143
object<Input>() -> impl Parser<Input, Output = Value> where Input: Stream<Token = char>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,144 fn object<Input>() -> impl Parser<Input, Output = Value>
145 where
146 Input: Stream<Token = char>,
147 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
148 {
149 let field = (json_string(), lex(char(':')), json_value()).map(|t| (t.0, t.2));
150 let fields = sep_by(field, lex(char(',')));
151 between(lex(char('{')), lex(char('}')), fields)
152 .map(Value::Object)
153 .expected("object")
154 }
155
156 #[inline]
json_value<Input>() -> impl Parser<Input, Output = Value> where Input: Stream<Token = char>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,157 fn json_value<Input>() -> impl Parser<Input, Output = Value>
158 where
159 Input: Stream<Token = char>,
160 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
161 {
162 json_value_()
163 }
164
165 // We need to use `parser!` to break the recursive use of `value` to prevent the returned parser
166 // from containing itself
167 parser! {
168 #[inline]
169 fn json_value_[Input]()(Input) -> Value
170 where [ Input: Stream<Token = char> ]
171 {
172 let array = between(
173 lex(char('[')),
174 lex(char(']')),
175 sep_by(json_value(), lex(char(','))),
176 ).map(Value::Array);
177
178 choice((
179 json_string().map(Value::String),
180 object(),
181 array,
182 number().map(Value::Number),
183 lex(string("false").map(|_| Value::Bool(false))),
184 lex(string("true").map(|_| Value::Bool(true))),
185 lex(string("null").map(|_| Value::Null)),
186 ))
187 }
188 }
189
190 #[test]
json_test()191 fn json_test() {
192 use self::Value::*;
193
194 let input = r#"{
195 "array": [1, ""],
196 "object": {},
197 "number": 3.14,
198 "small_number": 0.59,
199 "int": -100,
200 "exp": -1e2,
201 "exp_neg": 23e-2,
202 "true": true,
203 "false" : false,
204 "null" : null
205 }"#;
206 let result = json_value().easy_parse(input);
207 let expected = Object(
208 vec![
209 ("array", Array(vec![Number(1.0), String("".to_string())])),
210 ("object", Object(HashMap::new())),
211 ("number", Number(3.14)),
212 ("small_number", Number(0.59)),
213 ("int", Number(-100.)),
214 ("exp", Number(-1e2)),
215 ("exp_neg", Number(23E-2)),
216 ("true", Bool(true)),
217 ("false", Bool(false)),
218 ("null", Null),
219 ]
220 .into_iter()
221 .map(|(k, v)| (k.to_string(), v))
222 .collect(),
223 );
224 match result {
225 Ok(result) => assert_eq!(result, (expected, "")),
226 Err(e) => {
227 println!("{}", e);
228 panic!();
229 }
230 }
231 }
232
test_data() -> String233 fn test_data() -> String {
234 let mut data = String::new();
235 File::open(&Path::new(&"benches/data.json"))
236 .and_then(|mut file| file.read_to_string(&mut data))
237 .unwrap();
238 data
239 }
240
bench_json(bencher: &mut Bencher<'_>)241 fn bench_json(bencher: &mut Bencher<'_>) {
242 let data = test_data();
243 let mut parser = json_value();
244 match parser.easy_parse(position::Stream::new(&data[..])) {
245 Ok((Value::Array(_), _)) => (),
246 Ok(_) => panic!(),
247 Err(err) => {
248 println!("{}", err);
249 panic!();
250 }
251 }
252 bencher.iter(|| {
253 let result = parser.easy_parse(position::Stream::new(&data[..]));
254 black_box(result)
255 });
256 }
257
bench_json_core_error(bencher: &mut Bencher<'_>)258 fn bench_json_core_error(bencher: &mut Bencher<'_>) {
259 let data = test_data();
260 let mut parser = json_value();
261 match parser.parse(position::Stream::new(&data[..])) {
262 Ok((Value::Array(_), _)) => (),
263 Ok(_) => panic!(),
264 Err(err) => {
265 println!("{}", err);
266 panic!();
267 }
268 }
269 bencher.iter(|| {
270 let result = parser.parse(position::Stream::new(&data[..]));
271 black_box(result)
272 });
273 }
274
bench_json_core_error_no_position(bencher: &mut Bencher<'_>)275 fn bench_json_core_error_no_position(bencher: &mut Bencher<'_>) {
276 let data = test_data();
277 let mut parser = json_value();
278 match parser.parse(&data[..]) {
279 Ok((Value::Array(_), _)) => (),
280 Ok(_) => panic!(),
281 Err(err) => {
282 println!("{}", err);
283 panic!();
284 }
285 }
286 bencher.iter(|| {
287 let result = parser.parse(&data[..]);
288 black_box(result)
289 });
290 }
291
bench_buffered_json(bencher: &mut Bencher<'_>)292 fn bench_buffered_json(bencher: &mut Bencher<'_>) {
293 let data = test_data();
294 bencher.iter(|| {
295 let buffer =
296 buffered::Stream::new(position::Stream::new(IteratorStream::new(data.chars())), 1);
297 let mut parser = json_value();
298 match parser.easy_parse(position::Stream::with_positioner(
299 buffer,
300 SourcePosition::default(),
301 )) {
302 Ok((Value::Array(v), _)) => {
303 black_box(v);
304 }
305 Ok(_) => panic!(),
306 Err(err) => {
307 println!("{}", err);
308 panic!();
309 }
310 }
311 });
312 }
313
bench(c: &mut Criterion)314 fn bench(c: &mut Criterion) {
315 c.bench_function("json", bench_json);
316 c.bench_function("json_core_error", bench_json_core_error);
317 c.bench_function(
318 "json_core_error_no_position",
319 bench_json_core_error_no_position,
320 );
321 c.bench_function("buffered_json", bench_buffered_json);
322 }
323
324 criterion_group!(json, bench);
325 criterion_main!(json);
326