1 | use std::ptr::NonNull; |
2 | |
3 | use crate::{benchmark::BenchArgsRunner, Bencher}; |
4 | |
5 | mod generic; |
6 | mod list; |
7 | mod meta; |
8 | mod tree; |
9 | |
10 | pub use self::{ |
11 | generic::{EntryConst, EntryType, GenericBenchEntry}, |
12 | list::EntryList, |
13 | meta::{EntryLocation, EntryMeta}, |
14 | }; |
15 | pub(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`. |
21 | pub static BENCH_ENTRIES: EntryList<BenchEntry> = EntryList::root(); |
22 | |
23 | /// Group entries generated by `#[divan::bench_group]`. |
24 | pub static GROUP_ENTRIES: EntryList<GroupEntry> = EntryList::root(); |
25 | |
26 | /// Determines how the benchmark entry is run. |
27 | #[derive (Clone, Copy)] |
28 | pub 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]`. |
37 | pub 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]`. |
47 | pub 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 | |
59 | impl 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)] |
67 | pub(crate) enum AnyBenchEntry<'a> { |
68 | Bench(&'a BenchEntry), |
69 | GenericBench(&'a GenericBenchEntry), |
70 | } |
71 | |
72 | impl<'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 | |