mobench_sdk/registry.rs
1//! Benchmark function registry
2//!
3//! This module provides runtime discovery of benchmark functions that have been
4//! marked with the `#[benchmark]` attribute macro.
5
6use crate::timing::{BenchReport, BenchSpec, TimingError};
7
8/// A registered benchmark function
9///
10/// This struct is submitted to the global registry by the `#[benchmark]` macro.
11/// It contains the function's name and a runner that executes the benchmark.
12pub struct BenchFunction {
13 /// Fully-qualified name of the benchmark function (e.g., "my_crate::my_module::my_bench")
14 pub name: &'static str,
15
16 /// Runner function that executes the benchmark with timing
17 ///
18 /// Takes a BenchSpec and returns a BenchReport directly.
19 /// The runner handles setup/teardown internally.
20 pub runner: fn(BenchSpec) -> Result<BenchReport, TimingError>,
21}
22
23// Register the BenchFunction type with inventory
24inventory::collect!(BenchFunction);
25
26/// Discovers all registered benchmark functions
27///
28/// Returns a vector of references to all functions that have been marked with
29/// the `#[benchmark]` attribute in the current binary.
30///
31/// # Example
32///
33/// ```no_run
34/// use mobench_sdk::registry::discover_benchmarks;
35///
36/// fn main() {
37/// let benchmarks = discover_benchmarks();
38/// for bench in benchmarks {
39/// println!("Found benchmark: {}", bench.name);
40/// }
41/// }
42/// ```
43pub fn discover_benchmarks() -> Vec<&'static BenchFunction> {
44 inventory::iter::<BenchFunction>().collect()
45}
46
47/// Finds a benchmark function by name
48///
49/// Searches the registry for a function with the given name. Supports both
50/// short names (e.g., "fibonacci") and fully-qualified names
51/// (e.g., "my_crate::fibonacci").
52///
53/// # Arguments
54///
55/// * `name` - The name of the benchmark to find
56///
57/// # Returns
58///
59/// * `Some(&BenchFunction)` if found
60/// * `None` if no matching benchmark exists
61///
62/// # Example
63///
64/// ```no_run
65/// use mobench_sdk::registry::find_benchmark;
66///
67/// fn main() {
68/// if let Some(bench) = find_benchmark("fibonacci") {
69/// println!("Found benchmark: {}", bench.name);
70/// } else {
71/// eprintln!("Benchmark not found");
72/// }
73/// }
74/// ```
75pub fn find_benchmark(name: &str) -> Option<&'static BenchFunction> {
76 inventory::iter::<BenchFunction>().find(|f| {
77 // Match either the full name or just the final component
78 f.name == name || f.name.ends_with(&format!("::{}", name))
79 })
80}
81
82/// Lists all registered benchmark names
83///
84/// Returns a sorted vector of all benchmark function names in the registry.
85///
86/// # Example
87///
88/// ```no_run
89/// use mobench_sdk::registry::list_benchmark_names;
90///
91/// fn main() {
92/// let names = list_benchmark_names();
93/// println!("Available benchmarks:");
94/// for name in names {
95/// println!(" - {}", name);
96/// }
97/// }
98/// ```
99pub fn list_benchmark_names() -> Vec<&'static str> {
100 let mut names: Vec<&'static str> = inventory::iter::<BenchFunction>().map(|f| f.name).collect();
101 names.sort();
102 names
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_discover_benchmarks() {
111 // Note: This test validates that the discovery function works
112 // The number of benchmarks depends on what's registered in the binary
113 let benchmarks = discover_benchmarks();
114 // Just ensure the function returns successfully
115 let _ = benchmarks;
116 }
117
118 #[test]
119 fn test_find_benchmark_none() {
120 // Should not find a non-existent benchmark
121 let result = find_benchmark("nonexistent_benchmark_function_12345");
122 assert!(result.is_none());
123 }
124
125 #[test]
126 fn test_list_benchmark_names() {
127 // Validates that the function returns successfully
128 let names = list_benchmark_names();
129 let _ = names;
130 }
131}