use aspect_std::AllowlistAspect;
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use std::hint::black_box;
fn make_entries(n: usize, include_target: bool) -> Vec<String> {
let mut v: Vec<String> = (0..n).map(|i| format!("{}", 100_000_000 + i as u64)).collect();
if include_target {
v.pop();
v.push("999999999".to_string());
}
v
}
#[inline]
fn baseline_is_allowed(entries: &[String], identity: &str) -> bool {
entries.iter().any(|u| u == "*" || u == identity)
}
const DISCORD_PAYLOAD: &[u8] = br#"{
"id": "1234567890123456789",
"channel_id": "987654321098765432",
"guild_id": "555555555555555555",
"author": {
"id": "999999999",
"username": "alice",
"discriminator": "0001",
"avatar": "abc123def456",
"bot": false,
"system": false,
"global_name": "Alice"
},
"member": {
"nick": null,
"roles": ["111111111111111111", "222222222222222222"],
"joined_at": "2024-01-15T10:00:00.000000+00:00",
"premium_since": null,
"deaf": false,
"mute": false
},
"content": "hello bot, please answer this short question",
"timestamp": "2026-05-13T20:00:00.000000+00:00",
"edited_timestamp": null,
"tts": false,
"mention_everyone": false,
"mentions": [],
"mention_roles": [],
"attachments": [],
"embeds": [],
"pinned": false,
"type": 0
}"#;
#[inline(always)]
fn parse_and_extract_author(payload: &[u8]) -> String {
let v: serde_json::Value = serde_json::from_slice(payload).expect("parse");
v.get("author")
.and_then(|a| a.get("id"))
.and_then(|i| i.as_str())
.expect("author.id")
.to_string()
}
fn bench_per_message(c: &mut Criterion) {
let mut group = c.benchmark_group("per_message");
group.sample_size(500);
let cases: &[(&str, usize, bool)] = &[
("hit_small", 8, true),
("hit_large", 256, true),
("miss_small", 8, false),
("miss_large", 256, false),
];
for &(name, n, include_target) in cases {
let entries = make_entries(n, include_target);
let aspect = AllowlistAspect::new(entries.clone());
group.bench_with_input(
BenchmarkId::new("baseline", name),
&(entries.clone()),
|b, e| {
b.iter(|| {
let id = parse_and_extract_author(black_box(DISCORD_PAYLOAD));
black_box(baseline_is_allowed(e, &id))
});
},
);
group.bench_with_input(
BenchmarkId::new("aspect", name),
&aspect,
|b, a| {
b.iter(|| {
let id = parse_and_extract_author(black_box(DISCORD_PAYLOAD));
black_box(a.is_allowed(&id))
});
},
);
}
{
let entries = vec!["*".to_string()];
let aspect = AllowlistAspect::new(entries.clone());
group.bench_function("baseline/wildcard", |b| {
b.iter(|| {
let id = parse_and_extract_author(black_box(DISCORD_PAYLOAD));
black_box(baseline_is_allowed(&entries, &id))
});
});
group.bench_function("aspect/wildcard", |b| {
b.iter(|| {
let id = parse_and_extract_author(black_box(DISCORD_PAYLOAD));
black_box(aspect.is_allowed(&id))
});
});
}
group.finish();
}
criterion_group!(benches, bench_per_message);
criterion_main!(benches);