1use std::ptr::NonNull;
2
3use crate::{benchmark::BenchArgsRunner, Bencher};
4
5mod generic;
6mod list;
7mod meta;
8mod tree;
9
10pub use self::{
11 generic::{EntryConst, EntryType, GenericBenchEntry},
12 list::EntryList,
13 meta::{EntryLocation, EntryMeta},
14};
15pub(crate) use tree::EntryTree;
16
17/// Benchmark entries generated by `#[divan::bench]`.
18///
19/// Note: generic-type benchmark entries are instead stored in `GROUP_ENTRIES`
20/// in `generic_benches`.
21pub static BENCH_ENTRIES: EntryList<BenchEntry> = EntryList::root();
22
23/// Group entries generated by `#[divan::bench_group]`.
24pub static GROUP_ENTRIES: EntryList<GroupEntry> = EntryList::root();
25
26/// Determines how the benchmark entry is run.
27#[derive(Clone, Copy)]
28pub enum BenchEntryRunner {
29 /// Benchmark without arguments.
30 Plain(fn(Bencher)),
31
32 /// Benchmark with runtime arguments.
33 Args(fn() -> BenchArgsRunner),
34}
35
36/// Compile-time entry for a benchmark, generated by `#[divan::bench]`.
37pub struct BenchEntry {
38 /// Entry metadata.
39 pub meta: EntryMeta,
40
41 /// The benchmarking function.
42 pub bench: BenchEntryRunner,
43}
44
45/// Compile-time entry for a benchmark group, generated by
46/// `#[divan::bench_group]` or a generic-type `#[divan::bench]`.
47pub struct GroupEntry {
48 /// Entry metadata.
49 pub meta: EntryMeta,
50
51 /// Generic `#[divan::bench]` entries.
52 ///
53 /// This is two-dimensional to make code generation simpler. The outer
54 /// dimension corresponds to types and the inner dimension corresponds to
55 /// constants.
56 pub generic_benches: Option<&'static [&'static [GenericBenchEntry]]>,
57}
58
59impl GroupEntry {
60 pub(crate) fn generic_benches_iter(&self) -> impl Iterator<Item = &'static GenericBenchEntry> {
61 self.generic_benches.unwrap_or_default().iter().flat_map(|benches: &&[GenericBenchEntry]| benches.iter())
62 }
63}
64
65/// `BenchEntry` or `GenericBenchEntry`.
66#[derive(Clone, Copy)]
67pub(crate) enum AnyBenchEntry<'a> {
68 Bench(&'a BenchEntry),
69 GenericBench(&'a GenericBenchEntry),
70}
71
72impl<'a> AnyBenchEntry<'a> {
73 /// Returns a pointer to use as the identity of the entry.
74 #[inline]
75 pub fn entry_addr(self) -> NonNull<()> {
76 match self {
77 Self::Bench(entry) => NonNull::from(entry).cast(),
78 Self::GenericBench(entry) => NonNull::from(entry).cast(),
79 }
80 }
81
82 /// Returns this entry's benchmark runner.
83 #[inline]
84 pub fn bench_runner(self) -> &'a BenchEntryRunner {
85 match self {
86 Self::Bench(BenchEntry { bench, .. })
87 | Self::GenericBench(GenericBenchEntry { bench, .. }) => bench,
88 }
89 }
90
91 /// Returns this entry's argument names.
92 #[inline]
93 pub fn arg_names(self) -> Option<&'static [&'static str]> {
94 match self.bench_runner() {
95 BenchEntryRunner::Args(bench_runner) => {
96 let bench_runner = bench_runner();
97 Some(bench_runner.arg_names())
98 }
99 _ => None,
100 }
101 }
102
103 #[inline]
104 pub fn meta(self) -> &'a EntryMeta {
105 match self {
106 Self::Bench(entry) => &entry.meta,
107 Self::GenericBench(entry) => &entry.group.meta,
108 }
109 }
110
111 #[inline]
112 pub fn raw_name(self) -> &'a str {
113 match self {
114 Self::Bench(entry) => entry.meta.raw_name,
115 Self::GenericBench(entry) => entry.raw_name(),
116 }
117 }
118
119 #[inline]
120 pub fn display_name(self) -> &'a str {
121 match self {
122 Self::Bench(entry) => entry.meta.display_name,
123 Self::GenericBench(entry) => entry.display_name(),
124 }
125 }
126}
127