1 use {
2     crate::*,
3 };
4 
5 /// Generates a benchmark with a consistent id
6 /// (using the benchmark file title), calling
7 /// the benchmarking functions given in argument.
8 ///
9 /// ```no-test
10 /// glassbench!(
11 ///     "Sortings",
12 ///     bench_number_sorting,
13 ///     bench_alpha_sorting,
14 /// );
15 /// ```
16 ///
17 /// This generates the whole main function.
18 /// If you want to set the bench name yourself
19 /// (not recommanded), or change the way the launch
20 /// arguments are used, you can write the main
21 /// yourself and call [create_bench] and [after_bench]
22 /// instead of using this macro.
23 #[macro_export]
24 macro_rules! glassbench {
25     (
26         $title: literal,
27         $( $fun: path, )+
28     ) => {
29         pub fn main() {
30             use glassbench::*;
31             let name = env!("CARGO_CRATE_NAME");
32             let cmd = Command::read();
33             if cmd.include_bench(&name) {
34                 let mut bench = create_bench(name, $title, &cmd);
35                 $(
36                     $fun(&mut bench);
37                 )+
38                 if let Err(e) = after_bench(&mut bench, &cmd) {
39                     eprintln!("{}", e);
40                 }
41             } else {
42                 println!("skipping bench {:?}", &name);
43             }
44         }
45     }
46 }
47 
48 /// Create a bench with a user defined name (instead of
49 /// the file name) and command (instead of the one read in
50 /// arguments)
51 ///
52 /// Unless you have special reasons, you should not
53 /// use this function but the [glassbench!] function.
create_bench<S1, S2>( name: S1, title: S2, cmd: &Command, ) -> Bench where S1: Into<String>, S2: Into<String>,54 pub fn create_bench<S1, S2>(
55     name: S1,
56     title: S2,
57     cmd: &Command,
58 ) -> Bench
59 where
60     S1: Into<String>,
61     S2: Into<String>,
62 {
63     let mut bench = Bench::new(name, title);
64     bench.tag = cmd.tag.clone();
65     bench
66 }
67 
68 /// Print the tabular report for the executed benchmark
69 /// then graph, list history, and or save according to
70 /// command
71 ///
72 /// Unless you have special reasons, you should not
73 /// use this function but the [glassbench!] function.
after_bench( bench: &mut Bench, cmd: &Command, ) -> Result<(), GlassBenchError>74 pub fn after_bench(
75     bench: &mut Bench,
76     cmd: &Command,
77 ) -> Result<(), GlassBenchError> {
78     let printer = Printer::new();
79     let mut db = Db::open()?;
80     let previous = db.last_bench_named(&bench.name)?;
81     let report = Report::new(&bench, &previous);
82     report.print(&printer);
83     let mut no_save = cmd.no_save;
84     if let Some(graph_arg) = cmd.graph.as_ref() {
85         let task_name = bench.task_name_from_arg(graph_arg);
86         let viewer = HtmlViewer::new(&bench.name, task_name);
87         viewer.open_in_browser()?;
88         no_save = true;
89     }
90     if let Some(tbl_arg) = cmd.history.as_ref() {
91         let history = bench.task_history(&mut db, tbl_arg)?;
92         let tbl = HistoryTbl::new(&history);
93         tbl.print(&printer);
94         no_save = true;
95     }
96     if !no_save {
97         db.save_bench(&bench)?;
98     }
99     Ok(())
100 }
101