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