• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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