#![allow(clippy::unwrap_used)] use std::collections::HashMap; use syntaxe::*; #[derive(Debug, PartialEq)] enum Json { Null, Bool(bool), Number(f64), Str(String), Array(Vec), Object(HashMap), } fn json_parser<'a>() -> impl Parser<'a, Output = Json> { |input| json_value().parse_at(input) } fn json_value<'a>() -> impl Parser<'a, Output = Json> { string("null") .map(|_| Json::Null) .or(string("true").map(|_| Json::Bool(true))) .or(string("false").map(|_| Json::Bool(false))) .or(json_number()) .or(json_string().map(Json::Str)) .or(json_array()) .or(json_object()) } fn json_number<'a>() -> impl Parser<'a, Output = Json> { signed(float::()) .map(Json::Number) .or(signed(natural::()).map(|i| Json::Number(i as f64))) } fn json_string<'a>() -> impl Parser<'a, Output = String> { let escaped_char = symbol('\\') .then(choice([ symbol('"').value('"'), symbol('\\').value('\\'), symbol('/').value('/'), symbol('n').value('\n'), symbol('t').value('\t'), ])) .map(|(_, c)| c); let string_char = escaped_char.or(satisfy(|c| *c != '"' && *c != '\\')); between(symbol('"'), symbol('"'), many::<_, String>(string_char)) } fn json_array<'a>() -> impl Parser<'a, Output = Json> { between( symbol('[').skip(whitespace()), whitespace().then(symbol(']')), (|input| json_value().skip(whitespace()).parse_at(input)) .delimited_by(symbol(',').skip(whitespace())), ) .map(Json::Array) } fn json_object<'a>() -> impl Parser<'a, Output = Json> { let key_value = json_string() .skip(symbol(':')) .skip(whitespace()) .then(|input| json_value().parse_at(input)) .skip(whitespace()); between( symbol('{').then(whitespace()), whitespace().then(symbol('}')), key_value.delimited_by(symbol(',').skip(whitespace())), ) .map(|pairs| Json::Object(pairs.into_iter().collect())) } fn main() { use benchmark_simple as bs; let input = include_str!("twitter.json"); let size = input.bytes().len(); let bench = bs::Bench::new(); let options = bs::Options::default(); let parser = json_parser(); let result = bench.run(&options, || { parser.parse(bs::black_box(input)).unwrap(); }); let t = result.throughput_bytes(size as u128).as_mb(); eprintln!("{t:.1}MB/s"); }