1#[global_allocator]
2static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
3
4use criterion::*;
5
6use nom::{
7  bytes::complete::{is_a, tag, take_till, take_while},
8  character::complete::{alphanumeric1 as alphanumeric, char, not_line_ending, space0 as space},
9  combinator::opt,
10  multi::many0,
11  sequence::{delimited, pair, terminated, tuple},
12  IResult,
13};
14
15use std::collections::HashMap;
16
17fn is_line_ending_or_comment(chr: char) -> bool {
18  chr == ';' || chr == '\n'
19}
20
21fn space_or_line_ending(i: &str) -> IResult<&str, &str> {
22  is_a(" \r\n")(i)
23}
24
25fn category(i: &str) -> IResult<&str, &str> {
26  terminated(
27    delimited(char('['), take_while(|c| c != ']'), char(']')),
28    opt(is_a(" \r\n")),
29  )(i)
30}
31
32fn key_value(i: &str) -> IResult<&str, (&str, &str)> {
33  let (i, key) = alphanumeric(i)?;
34  let (i, _) = tuple((opt(space), tag("="), opt(space)))(i)?;
35  let (i, val) = take_till(is_line_ending_or_comment)(i)?;
36  let (i, _) = opt(space)(i)?;
37  let (i, _) = opt(pair(tag(";"), not_line_ending))(i)?;
38  let (i, _) = opt(space_or_line_ending)(i)?;
39  Ok((i, (key, val)))
40}
41
42fn keys_and_values_aggregator(i: &str) -> IResult<&str, Vec<(&str, &str)>> {
43  many0(key_value)(i)
44}
45
46fn keys_and_values(input: &str) -> IResult<&str, HashMap<&str, &str>> {
47  match keys_and_values_aggregator(input) {
48    Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())),
49    Err(e) => Err(e),
50  }
51}
52
53fn category_and_keys(i: &str) -> IResult<&str, (&str, HashMap<&str, &str>)> {
54  pair(category, keys_and_values)(i)
55}
56
57fn categories_aggregator(i: &str) -> IResult<&str, Vec<(&str, HashMap<&str, &str>)>> {
58  many0(category_and_keys)(i)
59}
60
61fn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str>>> {
62  match categories_aggregator(input) {
63    Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())),
64    Err(e) => Err(e),
65  }
66}
67
68fn bench_ini_str(c: &mut Criterion) {
69  let s = "[owner]
70name=John Doe
71organization=Acme Widgets Inc.
72
73[database]
74server=192.0.2.62
75port=143
76file=payroll.dat
77";
78
79  let mut group = c.benchmark_group("ini str");
80  group.throughput(Throughput::Bytes(s.len() as u64));
81  group.bench_function(BenchmarkId::new("parse", s.len()), |b| {
82    b.iter(|| categories(s).unwrap())
83  });
84}
85
86criterion_group!(benches, bench_ini_str);
87criterion_main!(benches);
88