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