use std::hint::black_box;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use reddb_types::Value;
fn write_display(value: &Value, out: &mut String) {
match value {
Value::Array(elems) => {
out.push('[');
for (i, elem) in elems.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
write_display(elem, out);
}
out.push(']');
}
other => out.push_str(&other.display_string()),
}
}
fn write_plain(value: &Value, out: &mut String) {
match value {
Value::Array(elems) => {
out.push('[');
for (i, elem) in elems.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
write_plain(elem, out);
}
out.push(']');
}
Value::Text(text) => out.push_str(text),
other => out.push_str(&other.display_string()),
}
}
fn candidate_display(value: &Value) -> String {
let mut out = String::new();
write_display(value, &mut out);
out
}
fn candidate_plain(value: &Value) -> String {
let mut out = String::new();
write_plain(value, &mut out);
out
}
fn scalar_array(n: usize) -> Value {
let elems = (0..n)
.map(|i| match i % 3 {
0 => Value::Integer(i as i64),
1 => Value::Float(i as f64 * 1.5),
_ => Value::Boolean(i % 2 == 0),
})
.collect();
Value::Array(elems)
}
fn nested_array(outer: usize, inner: usize) -> Value {
let elems = (0..outer).map(|_| scalar_array(inner)).collect();
Value::Array(elems)
}
fn mixed_array(n: usize) -> Value {
let elems = (0..n)
.map(|i| match i % 4 {
0 => Value::text(format!("item-{i}")),
1 => Value::Integer(i as i64),
2 => Value::Float(i as f64),
_ => scalar_array(4),
})
.collect();
Value::Array(elems)
}
fn bench_display(c: &mut Criterion) {
let cases: Vec<(&str, Value)> = vec![
("scalar/16", scalar_array(16)),
("scalar/256", scalar_array(256)),
("nested/16x16", nested_array(16, 16)),
("mixed/64", mixed_array(64)),
];
let mut group = c.benchmark_group("array_display_string");
for (name, value) in &cases {
assert_eq!(
value.display_string(),
candidate_display(value),
"candidate display must equal baseline for {name}"
);
let elems = match value {
Value::Array(e) => e.len() as u64,
_ => 1,
};
group.throughput(Throughput::Elements(elems));
group.bench_with_input(BenchmarkId::new("baseline", name), value, |b, v| {
b.iter(|| black_box(black_box(v).display_string()))
});
group.bench_with_input(BenchmarkId::new("direct_write", name), value, |b, v| {
b.iter(|| black_box(candidate_display(black_box(v))))
});
}
group.finish();
}
fn bench_plain(c: &mut Criterion) {
let cases: Vec<(&str, Value)> = vec![
("scalar/16", scalar_array(16)),
("scalar/256", scalar_array(256)),
("nested/16x16", nested_array(16, 16)),
("mixed/64", mixed_array(64)),
];
let mut group = c.benchmark_group("array_plain_text");
for (name, value) in &cases {
assert_eq!(
value.plain_text(),
candidate_plain(value),
"candidate plain_text must equal baseline for {name}"
);
let elems = match value {
Value::Array(e) => e.len() as u64,
_ => 1,
};
group.throughput(Throughput::Elements(elems));
group.bench_with_input(BenchmarkId::new("baseline", name), value, |b, v| {
b.iter(|| black_box(black_box(v).plain_text()))
});
group.bench_with_input(BenchmarkId::new("direct_write", name), value, |b, v| {
b.iter(|| black_box(candidate_plain(black_box(v))))
});
}
group.finish();
}
criterion_group!(benches, bench_display, bench_plain);
criterion_main!(benches);