Skip to main content

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/// ```ignore
34/// use mobench_sdk::registry::discover_benchmarks;
35///
36/// let benchmarks = discover_benchmarks();
37/// for bench in benchmarks {
38///     println!("Found benchmark: {}", bench.name);
39/// }
40/// ```
41pub fn discover_benchmarks() -> Vec<&'static BenchFunction> {
42    inventory::iter::<BenchFunction>().collect()
43}
44
45/// Finds a benchmark function by name
46///
47/// Searches the registry for a function with the given name. Supports both
48/// short names (e.g., "fibonacci") and fully-qualified names
49/// (e.g., "my_crate::fibonacci").
50///
51/// # Arguments
52///
53/// * `name` - The name of the benchmark to find
54///
55/// # Returns
56///
57/// * `Some(&BenchFunction)` if found
58/// * `None` if no matching benchmark exists
59///
60/// # Example
61///
62/// ```ignore
63/// use mobench_sdk::registry::find_benchmark;
64///
65/// if let Some(bench) = find_benchmark("fibonacci") {
66///     println!("Found benchmark: {}", bench.name);
67/// } else {
68///     eprintln!("Benchmark not found");
69/// }
70/// ```
71pub fn find_benchmark(name: &str) -> Option<&'static BenchFunction> {
72    inventory::iter::<BenchFunction>().find(|f| {
73        // Match either the full name or just the final component
74        f.name == name || f.name.ends_with(&format!("::{}", name))
75    })
76}
77
78/// Lists all registered benchmark names
79///
80/// Returns a sorted vector of all benchmark function names in the registry.
81///
82/// # Example
83///
84/// ```ignore
85/// use mobench_sdk::registry::list_benchmark_names;
86///
87/// let names = list_benchmark_names();
88/// println!("Available benchmarks:");
89/// for name in names {
90///     println!("  - {}", name);
91/// }
92/// ```
93pub fn list_benchmark_names() -> Vec<&'static str> {
94    let mut names: Vec<&'static str> = inventory::iter::<BenchFunction>().map(|f| f.name).collect();
95    names.sort();
96    names
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_discover_benchmarks() {
105        // Note: This test validates that the discovery function works
106        // The number of benchmarks depends on what's registered in the binary
107        let benchmarks = discover_benchmarks();
108        // Just ensure the function returns successfully
109        let _ = benchmarks;
110    }
111
112    #[test]
113    fn test_find_benchmark_none() {
114        // Should not find a non-existent benchmark
115        let result = find_benchmark("nonexistent_benchmark_function_12345");
116        assert!(result.is_none());
117    }
118
119    #[test]
120    fn test_list_benchmark_names() {
121        // Validates that the function returns successfully
122        let names = list_benchmark_names();
123        let _ = names;
124    }
125}