mod generic;
use std::{
ptr,
sync::{
atomic::{AtomicPtr, Ordering as AtomicOrdering},
LazyLock,
},
};
use super::{
bench::{BenchOptions, Bencher},
BenchArgsRunner,
};
pub use generic::{EntryConst, EntryType, GenericBenchEntry};
pub static BENCH_ENTRIES: EntryList<BenchEntry> = EntryList::root();
pub static GROUP_ENTRIES: EntryList<GroupEntry> = EntryList::root();
#[derive(Clone, Copy)]
pub enum BenchEntryRunner {
Plain(fn(Bencher)),
Args(fn() -> BenchArgsRunner),
}
pub struct BenchEntry {
pub meta: EntryMeta,
pub bench: BenchEntryRunner,
}
pub struct GroupEntry {
pub meta: EntryMeta,
pub generic_benches: Option<&'static [&'static [GenericBenchEntry]]>,
}
impl GroupEntry {
pub(crate) fn generic_benches_iter(&self) -> impl Iterator<Item = &'static GenericBenchEntry> {
self.generic_benches
.unwrap_or_default()
.iter()
.flat_map(|benches| benches.iter())
}
}
#[derive(Clone, Copy)]
pub(crate) enum AnyBenchEntry<'a> {
Bench(&'a BenchEntry),
GenericBench(&'a GenericBenchEntry),
}
pub struct EntryMeta {
pub display_name: &'static str,
pub raw_name: &'static str,
pub module_path: &'static str,
pub location: EntryLocation,
pub bench_options: Option<LazyLock<BenchOptions>>,
}
impl EntryMeta {
#[inline]
pub(crate) fn module_path_components<'a>(&self) -> impl Iterator<Item = &'a str> {
self.module_path.split("::")
}
}
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
#[allow(missing_docs)]
pub struct EntryLocation {
pub file: &'static str,
pub line: u32,
pub col: u32,
}
pub struct EntryList<T: 'static> {
entry: Option<&'static T>,
next: AtomicPtr<Self>,
}
impl<T> EntryList<T> {
pub(crate) const fn root() -> Self {
Self {
entry: None,
next: AtomicPtr::new(ptr::null_mut()),
}
}
#[inline]
fn next(&self) -> Option<&Self> {
unsafe { self.next.load(AtomicOrdering::Relaxed).as_ref() }
}
}
#[allow(missing_docs)]
impl<T> EntryList<T> {
#[inline]
pub const fn new(entry: &'static T) -> Self {
Self {
entry: Some(entry),
next: AtomicPtr::new(ptr::null_mut()),
}
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &T> {
let mut list = Some(self);
std::iter::from_fn(move || -> Option<Option<&T>> {
let current = list?;
list = current.next();
Some(current.entry.as_ref().copied())
})
.flatten()
}
#[inline]
pub fn push(&'static self, other: &'static Self) {
let mut old_next = self.next.load(AtomicOrdering::Relaxed);
loop {
other.next.store(old_next, AtomicOrdering::Release);
let other = other as *const Self as *mut Self;
match self.next.compare_exchange_weak(
old_next,
other,
AtomicOrdering::AcqRel,
AtomicOrdering::Acquire,
) {
Ok(_) => return,
Err(new) => old_next = new,
}
}
}
}
impl<'a> AnyBenchEntry<'a> {
#[inline]
pub fn bench_runner(self) -> &'a BenchEntryRunner {
match self {
Self::Bench(BenchEntry { bench, .. })
| Self::GenericBench(GenericBenchEntry { bench, .. }) => bench,
}
}
#[inline]
pub fn meta(self) -> &'a EntryMeta {
match self {
Self::Bench(entry) => &entry.meta,
Self::GenericBench(entry) => &entry.group.meta,
}
}
#[inline]
pub fn display_name(self) -> &'a str {
match self {
Self::Bench(entry) => entry.meta.display_name,
Self::GenericBench(entry) => entry.display_name(),
}
}
}