use criterion::{Criterion, criterion_group, criterion_main};
use once_cell::sync::Lazy;
use std::hint::black_box;
use std::time::Duration;
use string_pipeline::Template;
const SMALL_INPUT: &str = "apple,banana,cherry,date,elderberry,fig,grape,honeydew,kiwi,lemon";
const PADDED_SMALL_INPUT: &str = " apple , banana , cherry , date , elderberry ";
const USER_RECORD: &str = "john doe admin@example.com";
static LARGE_INPUT: Lazy<String> = Lazy::new(|| SMALL_INPUT.repeat(1_000)); static LARGE_MAP_INPUT: Lazy<String> = Lazy::new(|| PADDED_SMALL_INPUT.repeat(1_000));
fn bench_parsing(c: &mut Criterion) {
let cases = [
("single_block_simple", "{upper}"),
("single_block_chain", "{split:,:..|map:{trim|upper}|join:,}"),
(
"multi_section",
"User: {split: :0} Email: {split: :1} Fruits: {split:,:..|sort|join:\\|}",
),
(
"complex_nested",
"{split:,:..|filter:^[a-m]|map:{trim|upper|substring:0..3}|sort|join:,}",
),
("tv_path_last_segment", "{split:/:-1}"),
("tv_tabbed_display", "{split:\\t:0} ({split:\\t:2})"),
(
"tv_editor_command",
"${EDITOR:-vim} '+{strip_ansi|split:\\::1}' '{strip_ansi|split:\\::0}'",
),
(
"tv_pr_command",
"gh pr view {strip_ansi|split:#:1|split: :0} --web",
),
("tv_display_suffix", "{} - displayed"),
];
let mut group = c.benchmark_group("template_parsing");
for (name, tpl) in cases {
group.bench_function(name, |b| {
b.iter(|| Template::parse(black_box(tpl)).unwrap())
});
}
group.finish();
}
fn bench_execution(c: &mut Criterion) {
let cases = [
("single_block_upper_small", "{upper}", SMALL_INPUT),
("split_join_small", "{split:,:..|join: }", SMALL_INPUT),
("split_join_large", "{split:,:..|join: }", &LARGE_INPUT),
(
"multi_section_format",
"Name: {split: :0} Surname: {split: :1}",
USER_RECORD,
),
(
"repeated_split_sections",
"First: {split:,:0} Second: {split:,:1} Third: {split:,:2}",
SMALL_INPUT,
),
(
"filter_sort",
"{split:,:..|filter:^[a-m]|sort|join:,}",
SMALL_INPUT,
),
("map_upper", "{split:,:..|map:{upper}|join:,}", SMALL_INPUT),
(
"map_trim_upper_large",
"{split:,:..|map:{trim|upper}|join:,}",
&LARGE_MAP_INPUT,
),
(
"complex_nested",
"{split:,:..|filter:^[a-m]|map:{reverse|upper}|sort|join:,}",
SMALL_INPUT,
),
("tv_path_last_segment", "{split:/:-1}", "/a/b/c/d.txt"),
(
"tv_tabbed_display",
"{split:\\t:0} ({split:\\t:2})",
"api\tnginx:latest\tUp 2 hours",
),
(
"tv_editor_command",
"${EDITOR:-vim} '+{strip_ansi|split:\\::1}' '{strip_ansi|split:\\::0}'",
"src/main.rs:42:fn main()",
),
(
"tv_pr_command",
"gh pr view {strip_ansi|split:#:1|split: :0} --web",
"feature/add-benchmarks #123 ready",
),
("tv_display_suffix", "{} - displayed", "entry_12345"),
];
let mut group = c.benchmark_group("template_execution");
for (name, tpl_str, input) in cases {
let tpl = Template::parse(tpl_str).unwrap();
group.bench_function(name, |b| b.iter(|| tpl.format(black_box(input)).unwrap()));
}
group.finish();
}
fn bench_structured_inputs(c: &mut Criterion) {
let tpl = Template::parse("Users: {upper} | Files: {lower}").unwrap();
let user_inputs = ["john doe", "jane smith", "peter parker"];
let file_inputs = ["FILE1.TXT", "FILE2.TXT", "FILE3.TXT"];
let inputs: [&[&str]; 2] = [&user_inputs, &file_inputs];
let separators = [" ", ","];
let mut group = c.benchmark_group("structured_inputs");
group.bench_function("format_with_inputs", |b| {
b.iter(|| {
tpl.format_with_inputs(black_box(&inputs), black_box(&separators))
.unwrap()
})
});
group.finish();
}
criterion_group! {
name = benches;
config = Criterion::default()
.configure_from_args()
.sample_size(200)
.measurement_time(Duration::from_secs(5));
targets = bench_parsing, bench_execution, bench_structured_inputs
}
criterion_main!(benches);