16855e09eSopenharmony_ci#[macro_use]
26855e09eSopenharmony_ciextern crate criterion;
36855e09eSopenharmony_ci
46855e09eSopenharmony_ci#[global_allocator]
56855e09eSopenharmony_cistatic ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
66855e09eSopenharmony_ci
76855e09eSopenharmony_ciuse criterion::Criterion;
86855e09eSopenharmony_ciuse nom::{
96855e09eSopenharmony_ci  branch::alt,
106855e09eSopenharmony_ci  bytes::complete::{tag, take},
116855e09eSopenharmony_ci  character::complete::{anychar, char, multispace0, none_of},
126855e09eSopenharmony_ci  combinator::{map, map_opt, map_res, value, verify},
136855e09eSopenharmony_ci  error::{ErrorKind, ParseError},
146855e09eSopenharmony_ci  multi::{fold_many0, separated_list0},
156855e09eSopenharmony_ci  number::complete::{double, recognize_float},
166855e09eSopenharmony_ci  sequence::{delimited, preceded, separated_pair},
176855e09eSopenharmony_ci  IResult, Parser,
186855e09eSopenharmony_ci};
196855e09eSopenharmony_ci
206855e09eSopenharmony_ciuse std::collections::HashMap;
216855e09eSopenharmony_ci
226855e09eSopenharmony_ci#[derive(Debug, PartialEq, Clone)]
236855e09eSopenharmony_cipub enum JsonValue {
246855e09eSopenharmony_ci  Null,
256855e09eSopenharmony_ci  Bool(bool),
266855e09eSopenharmony_ci  Str(String),
276855e09eSopenharmony_ci  Num(f64),
286855e09eSopenharmony_ci  Array(Vec<JsonValue>),
296855e09eSopenharmony_ci  Object(HashMap<String, JsonValue>),
306855e09eSopenharmony_ci}
316855e09eSopenharmony_ci
326855e09eSopenharmony_cifn boolean(input: &str) -> IResult<&str, bool> {
336855e09eSopenharmony_ci  alt((value(false, tag("false")), value(true, tag("true"))))(input)
346855e09eSopenharmony_ci}
356855e09eSopenharmony_ci
366855e09eSopenharmony_cifn u16_hex(input: &str) -> IResult<&str, u16> {
376855e09eSopenharmony_ci  map_res(take(4usize), |s| u16::from_str_radix(s, 16))(input)
386855e09eSopenharmony_ci}
396855e09eSopenharmony_ci
406855e09eSopenharmony_cifn unicode_escape(input: &str) -> IResult<&str, char> {
416855e09eSopenharmony_ci  map_opt(
426855e09eSopenharmony_ci    alt((
436855e09eSopenharmony_ci      // Not a surrogate
446855e09eSopenharmony_ci      map(verify(u16_hex, |cp| !(0xD800..0xE000).contains(cp)), |cp| {
456855e09eSopenharmony_ci        cp as u32
466855e09eSopenharmony_ci      }),
476855e09eSopenharmony_ci      // See https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF for details
486855e09eSopenharmony_ci      map(
496855e09eSopenharmony_ci        verify(
506855e09eSopenharmony_ci          separated_pair(u16_hex, tag("\\u"), u16_hex),
516855e09eSopenharmony_ci          |(high, low)| (0xD800..0xDC00).contains(high) && (0xDC00..0xE000).contains(low),
526855e09eSopenharmony_ci        ),
536855e09eSopenharmony_ci        |(high, low)| {
546855e09eSopenharmony_ci          let high_ten = (high as u32) - 0xD800;
556855e09eSopenharmony_ci          let low_ten = (low as u32) - 0xDC00;
566855e09eSopenharmony_ci          (high_ten << 10) + low_ten + 0x10000
576855e09eSopenharmony_ci        },
586855e09eSopenharmony_ci      ),
596855e09eSopenharmony_ci    )),
606855e09eSopenharmony_ci    // Could probably be replaced with .unwrap() or _unchecked due to the verify checks
616855e09eSopenharmony_ci    std::char::from_u32,
626855e09eSopenharmony_ci  )(input)
636855e09eSopenharmony_ci}
646855e09eSopenharmony_ci
656855e09eSopenharmony_cifn character(input: &str) -> IResult<&str, char> {
666855e09eSopenharmony_ci  let (input, c) = none_of("\"")(input)?;
676855e09eSopenharmony_ci  if c == '\\' {
686855e09eSopenharmony_ci    alt((
696855e09eSopenharmony_ci      map_res(anychar, |c| {
706855e09eSopenharmony_ci        Ok(match c {
716855e09eSopenharmony_ci          '"' | '\\' | '/' => c,
726855e09eSopenharmony_ci          'b' => '\x08',
736855e09eSopenharmony_ci          'f' => '\x0C',
746855e09eSopenharmony_ci          'n' => '\n',
756855e09eSopenharmony_ci          'r' => '\r',
766855e09eSopenharmony_ci          't' => '\t',
776855e09eSopenharmony_ci          _ => return Err(()),
786855e09eSopenharmony_ci        })
796855e09eSopenharmony_ci      }),
806855e09eSopenharmony_ci      preceded(char('u'), unicode_escape),
816855e09eSopenharmony_ci    ))(input)
826855e09eSopenharmony_ci  } else {
836855e09eSopenharmony_ci    Ok((input, c))
846855e09eSopenharmony_ci  }
856855e09eSopenharmony_ci}
866855e09eSopenharmony_ci
876855e09eSopenharmony_cifn string(input: &str) -> IResult<&str, String> {
886855e09eSopenharmony_ci  delimited(
896855e09eSopenharmony_ci    char('"'),
906855e09eSopenharmony_ci    fold_many0(character, String::new, |mut string, c| {
916855e09eSopenharmony_ci      string.push(c);
926855e09eSopenharmony_ci      string
936855e09eSopenharmony_ci    }),
946855e09eSopenharmony_ci    char('"'),
956855e09eSopenharmony_ci  )(input)
966855e09eSopenharmony_ci}
976855e09eSopenharmony_ci
986855e09eSopenharmony_cifn ws<'a, O, E: ParseError<&'a str>, F: Parser<&'a str, O, E>>(f: F) -> impl Parser<&'a str, O, E> {
996855e09eSopenharmony_ci  delimited(multispace0, f, multispace0)
1006855e09eSopenharmony_ci}
1016855e09eSopenharmony_ci
1026855e09eSopenharmony_cifn array(input: &str) -> IResult<&str, Vec<JsonValue>> {
1036855e09eSopenharmony_ci  delimited(
1046855e09eSopenharmony_ci    char('['),
1056855e09eSopenharmony_ci    ws(separated_list0(ws(char(',')), json_value)),
1066855e09eSopenharmony_ci    char(']'),
1076855e09eSopenharmony_ci  )(input)
1086855e09eSopenharmony_ci}
1096855e09eSopenharmony_ci
1106855e09eSopenharmony_cifn object(input: &str) -> IResult<&str, HashMap<String, JsonValue>> {
1116855e09eSopenharmony_ci  map(
1126855e09eSopenharmony_ci    delimited(
1136855e09eSopenharmony_ci      char('{'),
1146855e09eSopenharmony_ci      ws(separated_list0(
1156855e09eSopenharmony_ci        ws(char(',')),
1166855e09eSopenharmony_ci        separated_pair(string, ws(char(':')), json_value),
1176855e09eSopenharmony_ci      )),
1186855e09eSopenharmony_ci      char('}'),
1196855e09eSopenharmony_ci    ),
1206855e09eSopenharmony_ci    |key_values| key_values.into_iter().collect(),
1216855e09eSopenharmony_ci  )(input)
1226855e09eSopenharmony_ci}
1236855e09eSopenharmony_ci
1246855e09eSopenharmony_cifn json_value(input: &str) -> IResult<&str, JsonValue> {
1256855e09eSopenharmony_ci  use JsonValue::*;
1266855e09eSopenharmony_ci
1276855e09eSopenharmony_ci  alt((
1286855e09eSopenharmony_ci    value(Null, tag("null")),
1296855e09eSopenharmony_ci    map(boolean, Bool),
1306855e09eSopenharmony_ci    map(string, Str),
1316855e09eSopenharmony_ci    map(double, Num),
1326855e09eSopenharmony_ci    map(array, Array),
1336855e09eSopenharmony_ci    map(object, Object),
1346855e09eSopenharmony_ci  ))(input)
1356855e09eSopenharmony_ci}
1366855e09eSopenharmony_ci
1376855e09eSopenharmony_cifn json(input: &str) -> IResult<&str, JsonValue> {
1386855e09eSopenharmony_ci  ws(json_value).parse(input)
1396855e09eSopenharmony_ci}
1406855e09eSopenharmony_ci
1416855e09eSopenharmony_cifn json_bench(c: &mut Criterion) {
1426855e09eSopenharmony_ci  let data = "  { \"a\"\t: 42,
1436855e09eSopenharmony_ci  \"b\": [ \"x\", \"y\", 12 ,\"\\u2014\", \"\\uD83D\\uDE10\"] ,
1446855e09eSopenharmony_ci  \"c\": { \"hello\" : \"world\"
1456855e09eSopenharmony_ci  }
1466855e09eSopenharmony_ci  }  ";
1476855e09eSopenharmony_ci
1486855e09eSopenharmony_ci  // println!("data:\n{:?}", json(data));
1496855e09eSopenharmony_ci  c.bench_function("json", |b| {
1506855e09eSopenharmony_ci    b.iter(|| json(data).unwrap());
1516855e09eSopenharmony_ci  });
1526855e09eSopenharmony_ci}
1536855e09eSopenharmony_ci
1546855e09eSopenharmony_cifn recognize_float_bytes(c: &mut Criterion) {
1556855e09eSopenharmony_ci  println!(
1566855e09eSopenharmony_ci    "recognize_float_bytes result: {:?}",
1576855e09eSopenharmony_ci    recognize_float::<_, (_, ErrorKind)>(&b"-1.234E-12"[..])
1586855e09eSopenharmony_ci  );
1596855e09eSopenharmony_ci  c.bench_function("recognize float bytes", |b| {
1606855e09eSopenharmony_ci    b.iter(|| recognize_float::<_, (_, ErrorKind)>(&b"-1.234E-12"[..]));
1616855e09eSopenharmony_ci  });
1626855e09eSopenharmony_ci}
1636855e09eSopenharmony_ci
1646855e09eSopenharmony_cifn recognize_float_str(c: &mut Criterion) {
1656855e09eSopenharmony_ci  println!(
1666855e09eSopenharmony_ci    "recognize_float_str result: {:?}",
1676855e09eSopenharmony_ci    recognize_float::<_, (_, ErrorKind)>("-1.234E-12")
1686855e09eSopenharmony_ci  );
1696855e09eSopenharmony_ci  c.bench_function("recognize float str", |b| {
1706855e09eSopenharmony_ci    b.iter(|| recognize_float::<_, (_, ErrorKind)>("-1.234E-12"));
1716855e09eSopenharmony_ci  });
1726855e09eSopenharmony_ci}
1736855e09eSopenharmony_ci
1746855e09eSopenharmony_cifn float_bytes(c: &mut Criterion) {
1756855e09eSopenharmony_ci  println!(
1766855e09eSopenharmony_ci    "float_bytes result: {:?}",
1776855e09eSopenharmony_ci    double::<_, (_, ErrorKind)>(&b"-1.234E-12"[..])
1786855e09eSopenharmony_ci  );
1796855e09eSopenharmony_ci  c.bench_function("float bytes", |b| {
1806855e09eSopenharmony_ci    b.iter(|| double::<_, (_, ErrorKind)>(&b"-1.234E-12"[..]));
1816855e09eSopenharmony_ci  });
1826855e09eSopenharmony_ci}
1836855e09eSopenharmony_ci
1846855e09eSopenharmony_cifn float_str(c: &mut Criterion) {
1856855e09eSopenharmony_ci  println!(
1866855e09eSopenharmony_ci    "float_str result: {:?}",
1876855e09eSopenharmony_ci    double::<_, (_, ErrorKind)>("-1.234E-12")
1886855e09eSopenharmony_ci  );
1896855e09eSopenharmony_ci  c.bench_function("float str", |b| {
1906855e09eSopenharmony_ci    b.iter(|| double::<_, (_, ErrorKind)>("-1.234E-12"));
1916855e09eSopenharmony_ci  });
1926855e09eSopenharmony_ci}
1936855e09eSopenharmony_ci
1946855e09eSopenharmony_ciuse nom::Err;
1956855e09eSopenharmony_ciuse nom::ParseTo;
1966855e09eSopenharmony_cifn std_float(input: &[u8]) -> IResult<&[u8], f64, (&[u8], ErrorKind)> {
1976855e09eSopenharmony_ci  match recognize_float(input) {
1986855e09eSopenharmony_ci    Err(e) => Err(e),
1996855e09eSopenharmony_ci    Ok((i, s)) => match s.parse_to() {
2006855e09eSopenharmony_ci      Some(n) => Ok((i, n)),
2016855e09eSopenharmony_ci      None => Err(Err::Error((i, ErrorKind::Float))),
2026855e09eSopenharmony_ci    },
2036855e09eSopenharmony_ci  }
2046855e09eSopenharmony_ci}
2056855e09eSopenharmony_ci
2066855e09eSopenharmony_cifn std_float_bytes(c: &mut Criterion) {
2076855e09eSopenharmony_ci  println!(
2086855e09eSopenharmony_ci    "std_float_bytes result: {:?}",
2096855e09eSopenharmony_ci    std_float(&b"-1.234E-12"[..])
2106855e09eSopenharmony_ci  );
2116855e09eSopenharmony_ci  c.bench_function("std_float bytes", |b| {
2126855e09eSopenharmony_ci    b.iter(|| std_float(&b"-1.234E-12"[..]));
2136855e09eSopenharmony_ci  });
2146855e09eSopenharmony_ci}
2156855e09eSopenharmony_ci
2166855e09eSopenharmony_cicriterion_group!(
2176855e09eSopenharmony_ci  benches,
2186855e09eSopenharmony_ci  json_bench,
2196855e09eSopenharmony_ci  recognize_float_bytes,
2206855e09eSopenharmony_ci  recognize_float_str,
2216855e09eSopenharmony_ci  float_bytes,
2226855e09eSopenharmony_ci  std_float_bytes,
2236855e09eSopenharmony_ci  float_str
2246855e09eSopenharmony_ci);
2256855e09eSopenharmony_cicriterion_main!(benches);
226