iai_callgrind/
macros.rs

1//! Contains macros which together define a benchmark harness that can be used in place of the
2//! standard benchmark harness. This allows the user to run Iai benchmarks with `cargo bench`.
3
4/// [low level api](`crate::binary_benchmark_group`) only: Use to add a `#[binary_benchmark]` to a
5/// [`crate::BinaryBenchmarkGroup`]
6///
7/// # Examples
8///
9/// ```rust
10/// # macro_rules! env { ($m:tt) => {{ "/some/path" }} }
11/// use iai_callgrind::{binary_benchmark_attribute, binary_benchmark_group, binary_benchmark};
12///
13/// #[binary_benchmark]
14/// fn bench_binary() -> iai_callgrind::Command {
15///     iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
16///         .arg("foo")
17///         .build()
18/// }
19///
20/// binary_benchmark_group!(
21///     name = my_group;
22///     benchmarks = |group: &mut BinaryBenchmarkGroup| {
23///         group.binary_benchmark(binary_benchmark_attribute!(bench_binary));
24///     }
25/// );
26/// # fn main() {}
27/// ```
28#[macro_export]
29macro_rules! binary_benchmark_attribute {
30    ($name:ident) => {{
31        let mut binary_benchmark = $crate::BinaryBenchmark::new(stringify!($name));
32        binary_benchmark.config = $name::__get_config();
33
34        for internal_bench in $name::__BENCHES {
35            let mut bench = if let Some(id) = internal_bench.id_display {
36                $crate::Bench::new(id)
37            } else {
38                $crate::Bench::new(stringify!($name))
39            };
40            let mut bench = bench.command((internal_bench.func)());
41            if let Some(setup) = internal_bench.setup {
42                bench.setup(setup);
43            }
44            if let Some(teardown) = internal_bench.teardown {
45                bench.teardown(teardown);
46            }
47            if let Some(config) = internal_bench.config {
48                bench.config(config());
49            }
50            binary_benchmark.bench(bench);
51        }
52        binary_benchmark
53    }};
54}
55
56/// The `iai_callgrind::main` macro expands to a `main` function which runs all the benchmarks.
57///
58/// Using Iai-callgrind requires disabling the benchmark harness. This can be done like so in the
59/// `Cargo.toml` file:
60///
61/// ```toml
62/// [[bench]]
63/// name = "my_bench"
64/// harness = false
65/// ```
66///
67/// To be able to run any iai-callgrind benchmarks, you'll also need the `iai-callgrind-runner`
68/// installed with the binary somewhere in your `$PATH` for example with
69///
70/// ```shell
71/// cargo install iai-callgrind-runner
72/// ```
73///
74/// `my_bench` has to be a rust file inside the 'benches' directory.
75///
76/// # Library Benchmarks
77///
78/// The [`crate::main`] macro has one form to run library benchmarks:
79///
80/// ```rust
81/// # use iai_callgrind::{main, library_benchmark_group, library_benchmark};
82/// # #[library_benchmark]
83/// # fn bench_fibonacci() { }
84/// # library_benchmark_group!(
85/// #    name = some_group;
86/// #    benchmarks = bench_fibonacci
87/// # );
88/// # fn main() {
89/// main!(library_benchmark_groups = some_group);
90/// # }
91/// ```
92///
93/// which accepts the following top-level arguments in this order (separated by a semicolon):
94///
95/// * __`config`__ (optional): Optionally specify a [`crate::LibraryBenchmarkConfig`] valid for all
96///   benchmark groups
97/// * __`setup`__ (optional): A setup function or any valid expression which is run before all
98///   benchmarks
99/// * __`teardown`__ (optional): A setup function or any valid expression which is run after all
100///   benchmarks
101/// * __`library_benchmark_groups`__ (mandatory): The __name__ of one or more
102///   [`library_benchmark_group!`](crate::library_benchmark_group) macros. Multiple __names__ are
103///   expected to be a comma separated list
104///
105/// A library benchmark consists of
106/// [`library_benchmark_groups`](crate::library_benchmark_group) and with
107/// [`#[library_benchmark]`](crate::library_benchmark) annotated benchmark functions.
108///
109/// ```rust
110/// use iai_callgrind::{main, library_benchmark_group, library_benchmark};
111/// use std::hint::black_box;
112///
113/// fn fibonacci(n: u64) -> u64 {
114///     match n {
115///         0 => 1,
116///         1 => 1,
117///         n => fibonacci(n - 1) + fibonacci(n - 2),
118///     }
119/// }
120///
121/// #[library_benchmark]
122/// #[bench::short(10)]
123/// #[bench::long(30)]
124/// fn bench_fibonacci(value: u64) -> u64 {
125///     black_box(fibonacci(value))
126/// }
127///
128/// library_benchmark_group!(
129///     name = bench_fibonacci_group;
130///     benchmarks = bench_fibonacci
131/// );
132///
133/// # fn main() {
134/// main!(library_benchmark_groups = bench_fibonacci_group);
135/// # }
136/// ```
137///
138/// If you need to pass arguments to valgrind's callgrind, you can specify callgrind arguments via
139/// [`crate::LibraryBenchmarkConfig::callgrind_args`]:
140///
141/// ```rust
142/// # use iai_callgrind::{main, library_benchmark_group, library_benchmark, LibraryBenchmarkConfig};
143/// # #[library_benchmark]
144/// # fn bench_fibonacci() { }
145/// # library_benchmark_group!(
146/// #    name = some_group;
147/// #    benchmarks = bench_fibonacci
148/// # );
149/// # fn main() {
150/// main!(
151///     config = LibraryBenchmarkConfig::default()
152///                 .callgrind_args(
153///                     ["--arg-with-flags=yes", "arg-without-flags=is_ok_too"]
154///                 );
155///     library_benchmark_groups = some_group
156/// );
157/// # }
158/// ```
159///
160/// See also [Callgrind Command-line
161/// options](https://valgrind.org/docs/manual/cl-manual.html#cl-manual.options).
162///
163/// For an in-depth description of library benchmarks and more examples see the
164/// [README#Library
165/// Benchmarks](https://github.com/iai-callgrind/iai-callgrind#library-benchmarks) of this
166/// crate.
167///
168/// # Binary Benchmarks
169///
170/// Setting up binary benchmarks is almost the same as setting up library benchmarks but using the
171/// `#[binary_benchmark]` macro. For example, if you're crate's binary is called `my-foo`:
172///
173/// ```rust
174/// # macro_rules! env { ($m:tt) => {{ "/some/path" }} }
175/// use iai_callgrind::{main, binary_benchmark_group, binary_benchmark};
176///
177/// #[binary_benchmark]
178/// #[bench::hello_world("hello world")]
179/// #[bench::foo("foo")]
180/// fn bench_binary(arg: &str) -> iai_callgrind::Command {
181///     iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
182///         .arg(arg)
183///         .build()
184/// }
185///
186/// binary_benchmark_group!(
187///     name = my_group;
188///     benchmarks = bench_binary
189/// );
190///
191/// # fn main() {
192/// main!(binary_benchmark_groups = my_group);
193/// # }
194/// ```
195///
196/// See the documentation of [`crate::binary_benchmark_group`] and [`crate::Command`] for more
197/// details.
198#[macro_export]
199macro_rules! main {
200    ( $( options = $( $options:literal ),+ $(,)*; )?
201      $( before = $before:ident $(, bench = $bench_before:literal )? ; )?
202      $( after = $after:ident $(, bench = $bench_after:literal )? ; )?
203      $( setup = $setup:ident $(, bench = $bench_setup:literal )? ; )?
204      $( teardown = $teardown:ident $(, bench = $bench_teardown:literal )? ; )?
205      $( sandbox = $sandbox:literal; )?
206      $( fixtures = $fixtures:literal $(, follow_symlinks = $follow_symlinks:literal )? ; )?
207      $( run = cmd = $cmd:expr
208            $(, envs = [ $( $envs:literal ),* $(,)* ] )?,
209            $( id = $id:literal, args = [ $( $args:literal ),* $(,)* ]  ),+ $(,)*
210      );+ $(;)*
211    ) => {
212        compile_error!(
213            "You are using a deprecated syntax of the main! macro to set up binary benchmarks. \
214            See the README (https://github.com/iai-callgrind/iai-callgrind) and \
215            docs (https://docs.rs/iai-callgrind/latest/iai_callgrind/) for further details."
216        );
217        pub fn main() {}
218    };
219    (
220        $( config = $config:expr; $(;)* )?
221        $( setup = $setup:expr ; $(;)* )?
222        $( teardown = $teardown:expr ; $(;)* )?
223        binary_benchmark_groups =
224    ) => {
225        compile_error!("The binary_benchmark_groups argument needs at least one `name` of a `binary_benchmark_group!`");
226    };
227    (
228        $( config = $config:expr; $(;)* )?
229        $( setup = $setup:expr ; $(;)* )?
230        $( teardown = $teardown:expr ; $(;)* )?
231        binary_benchmark_groups = $( $group:ident ),+ $(,)*
232    ) => {
233        fn __run() -> Result<(), $crate::error::Errors> {
234            let mut this_args = std::env::args();
235            let exe = option_env!("IAI_CALLGRIND_RUNNER")
236                .unwrap_or_else(|| option_env!("CARGO_BIN_EXE_iai-callgrind-runner").unwrap_or("iai-callgrind-runner"));
237
238            let library_version = "0.14.0";
239
240            let mut cmd = std::process::Command::new(exe);
241
242            cmd.arg(library_version);
243            cmd.arg("--bin-bench");
244            cmd.arg(env!("CARGO_MANIFEST_DIR"));
245            cmd.arg(env!("CARGO_PKG_NAME"));
246            cmd.arg(file!());
247            cmd.arg(module_path!());
248            cmd.arg(this_args.next().unwrap()); // The executable benchmark binary
249
250            let mut config: Option<$crate::internal::InternalBinaryBenchmarkConfig> = None;
251            $(
252                config = Some($config.into());
253            )?
254
255            let mut internal_benchmark_groups = $crate::internal::InternalBinaryBenchmarkGroups {
256                config: config.unwrap_or_default(),
257                command_line_args: this_args.collect(),
258                has_setup: __run_setup(false),
259                has_teardown: __run_teardown(false),
260                ..Default::default()
261            };
262
263            let mut errors = $crate::error::Errors::default();
264
265            $(
266                if $group::__IS_ATTRIBUTE {
267                    let mut internal_group = $crate::internal::InternalBinaryBenchmarkGroup {
268                        id: stringify!($group).to_owned(),
269                        config: $group::__get_config(),
270                        binary_benchmarks: vec![],
271                        has_setup: $group::__run_setup(false),
272                        has_teardown: $group::__run_teardown(false),
273                        compare_by_id: $group::__compare_by_id()
274                    };
275                    for (function_name, get_config, macro_bin_benches) in $group::__BENCHES {
276                        let mut internal_binary_benchmark =
277                            $crate::internal::InternalBinaryBenchmark {
278                                benches: vec![],
279                                config: get_config()
280                        };
281                        for macro_bin_bench in macro_bin_benches.iter() {
282                            let bench = $crate::internal::InternalBinaryBenchmarkBench {
283                                id: macro_bin_bench.id_display.map(|i| i.to_string()),
284                                args: macro_bin_bench.args_display.map(|i| i.to_string()),
285                                function_name: function_name.to_string(),
286                                command: (macro_bin_bench.func)().into(),
287                                config: macro_bin_bench.config.map(|f| f()),
288                                has_setup: macro_bin_bench.setup.is_some(),
289                                has_teardown: macro_bin_bench.teardown.is_some()
290                            };
291                            internal_binary_benchmark.benches.push(bench);
292                        }
293                        internal_group.binary_benchmarks.push(internal_binary_benchmark);
294                    }
295
296                    internal_benchmark_groups.groups.push(internal_group);
297                } else {
298                    let mut group = $crate::BinaryBenchmarkGroup::default();
299                    $group::$group(&mut group);
300
301                    let module_path = module_path!();
302
303                    let mut internal_group = $crate::internal::InternalBinaryBenchmarkGroup {
304                        id: stringify!($group).to_owned(),
305                        config: $group::__get_config(),
306                        binary_benchmarks: vec![],
307                        has_setup: $group::__run_setup(false),
308                        has_teardown: $group::__run_teardown(false),
309                        compare_by_id: $group::__compare_by_id()
310                    };
311
312                    let mut binary_benchmark_ids =
313                        std::collections::HashSet::<$crate::BenchmarkId>::new();
314
315                    if group.binary_benchmarks.is_empty() {
316                        errors.add(
317                            $crate::error::Error::GroupError(
318                                module_path.to_owned(),
319                                internal_group.id.clone(),
320                                "This group needs at least one benchmark".to_owned()
321                            )
322                        );
323                    }
324
325                    for binary_benchmark in group.binary_benchmarks {
326                        if let Err(message) = binary_benchmark.id.validate() {
327                            errors.add(
328                                $crate::error::Error::BinaryBenchmarkError(
329                                    module_path.to_owned(),
330                                    internal_group.id.clone(),
331                                    binary_benchmark.id.to_string(),
332                                    message
333                                )
334                            );
335                            continue;
336                        }
337                        if !binary_benchmark_ids.insert(binary_benchmark.id.clone()) {
338                            errors.add(
339                                $crate::error::Error::BinaryBenchmarkError(
340                                    module_path.to_owned(),
341                                    internal_group.id.clone(),
342                                    binary_benchmark.id.to_string(),
343                                    "Duplicate binary benchmark id".to_owned()
344                                )
345                            );
346                            continue;
347                        }
348
349                        let mut internal_binary_benchmark =
350                            $crate::internal::InternalBinaryBenchmark {
351                                benches: vec![],
352                                config: binary_benchmark.config.map(Into::into)
353                        };
354
355                        let mut bench_ids =
356                            std::collections::HashSet::<$crate::BenchmarkId>::new();
357
358                        if binary_benchmark.benches.is_empty() {
359                            errors.add(
360                                $crate::error::Error::BinaryBenchmarkError(
361                                    module_path.to_owned(),
362                                    internal_group.id.clone(),
363                                    binary_benchmark.id.to_string(),
364                                    "This binary benchmark needs at least one bench".to_owned()
365                                )
366                            );
367                        }
368
369                        for bench in binary_benchmark.benches {
370                            match bench.commands.as_slice() {
371                                [] => {
372                                    errors.add(
373                                        $crate::error::Error::BenchError(
374                                            module_path.to_owned(),
375                                            internal_group.id.clone(),
376                                            binary_benchmark.id.to_string(),
377                                            bench.id.to_string(),
378                                            "Missing command".to_owned()
379                                        )
380                                    );
381                                },
382                                [command] => {
383                                    if let Err(message) = bench.id.validate() {
384                                        errors.add(
385                                            $crate::error::Error::BenchError(
386                                                module_path.to_owned(),
387                                                internal_group.id.clone(),
388                                                binary_benchmark.id.to_string(),
389                                                bench.id.to_string(),
390                                                message
391                                            )
392                                        );
393                                    }
394                                    if !bench_ids.insert(bench.id.clone()) {
395                                        errors.add(
396                                            $crate::error::Error::BenchError(
397                                                module_path.to_owned(),
398                                                internal_group.id.clone(),
399                                                binary_benchmark.id.to_string(),
400                                                bench.id.to_string(),
401                                                format!("Duplicate id: '{}'", bench.id)
402                                            )
403                                        );
404                                    }
405                                    let internal_bench =
406                                        $crate::internal::InternalBinaryBenchmarkBench {
407                                            id: Some(bench.id.into()),
408                                            args: None,
409                                            function_name: binary_benchmark.id.clone().into(),
410                                            command: command.into(),
411                                            config: bench.config.clone(),
412                                            has_setup: bench.setup.is_some()
413                                                    || binary_benchmark.setup.is_some(),
414                                            has_teardown: bench.teardown.is_some()
415                                                    || binary_benchmark.teardown.is_some(),
416                                    };
417                                    internal_binary_benchmark.benches.push(internal_bench);
418                                },
419                                commands => {
420                                    for (index, command) in commands.iter().enumerate() {
421                                        let bench_id: $crate::BenchmarkId = format!("{}_{}", bench.id, index).into();
422                                        if let Err(message) = bench_id.validate() {
423                                            errors.add(
424                                                $crate::error::Error::BenchError(
425                                                    module_path.to_owned(),
426                                                    internal_group.id.clone(),
427                                                    binary_benchmark.id.to_string(),
428                                                    bench_id.to_string(),
429                                                    message
430                                                )
431                                            );
432                                            continue;
433                                        }
434                                        if !bench_ids.insert(bench_id.clone()) {
435                                            errors.add(
436                                                $crate::error::Error::BenchError(
437                                                    module_path.to_owned(),
438                                                    internal_group.id.clone(),
439                                                    binary_benchmark.id.to_string(),
440                                                    bench.id.to_string(),
441                                                    format!("Duplicate id: '{}'", bench_id)
442                                                )
443                                            );
444                                            continue;
445                                        }
446                                        let internal_bench =
447                                            $crate::internal::InternalBinaryBenchmarkBench {
448                                                id: Some(bench_id.into()),
449                                                args: None,
450                                                function_name: binary_benchmark.id.to_string(),
451                                                command: command.into(),
452                                                config: bench.config.clone(),
453                                                has_setup: bench.setup.is_some()
454                                                        || binary_benchmark.setup.is_some(),
455                                                has_teardown: bench.teardown.is_some()
456                                                        || binary_benchmark.teardown.is_some(),
457                                        };
458                                        internal_binary_benchmark.benches.push(internal_bench);
459                                    }
460                                }
461                            }
462                        }
463                        internal_group.binary_benchmarks.push(internal_binary_benchmark);
464                    }
465
466                    internal_benchmark_groups.groups.push(internal_group);
467                }
468            )+
469
470            if !errors.is_empty() {
471                return Err(errors);
472            }
473
474            let encoded = $crate::bincode::serialize(&internal_benchmark_groups).expect("Encoded benchmark");
475            let mut child = cmd
476                .arg(encoded.len().to_string())
477                .stdin(std::process::Stdio::piped())
478                .spawn()
479                .expect("Failed to run benchmarks. \
480                    Is iai-callgrind-runner installed and iai-callgrind-runner in your $PATH?. \
481                    You can also set the environment variable IAI_CALLGRIND_RUNNER to the \
482                    absolute path of the iai-callgrind-runner executable.");
483
484            let mut stdin = child.stdin.take().expect("Opening stdin to submit encoded benchmark");
485            std::thread::spawn(move || {
486                use std::io::Write;
487                stdin.write_all(&encoded).expect("Writing encoded benchmark to stdin");
488            });
489
490            let status = child.wait().expect("Wait for child process to exit");
491            if !status.success() {
492                std::process::exit(1);
493            }
494
495            Ok(())
496        }
497
498        fn __run_setup(__run: bool) -> bool {
499            let mut __has_setup = false;
500            $(
501                __has_setup = true;
502                if __run {
503                    $setup;
504                }
505            )?
506            __has_setup
507        }
508
509        fn __run_teardown(__run: bool) -> bool {
510            let mut __has_teardown = false;
511            $(
512                __has_teardown = true;
513                if __run {
514                    $teardown;
515                }
516            )?
517            __has_teardown
518        }
519
520        fn main() {
521            let mut args_iter = std::env::args().skip(1);
522            if args_iter
523                .next()
524                .as_ref()
525                .map_or(false, |value| value == "--iai-run")
526            {
527                let mut current = args_iter.next().expect("Expecting a function type");
528                let next = args_iter.next();
529                match (current.as_str(), next) {
530                    ("setup", None) => {
531                        __run_setup(true);
532                    },
533                    ("teardown", None) => {
534                        __run_teardown(true);
535                    },
536                    $(
537                        (group @ stringify!($group), Some(next)) => {
538                            let current = next;
539                            let next = args_iter.next();
540
541                            match (current.as_str(), next) {
542                                ("setup", None) => {
543                                    $group::__run_setup(true);
544                                },
545                                ("teardown", None) => {
546                                    $group::__run_teardown(true);
547                                }
548                                (key @ ("setup" | "teardown"), Some(next)) => {
549                                    let group_index = next
550                                            .parse::<usize>()
551                                            .expect("The group index should be a number");
552                                    let bench_index = args_iter
553                                            .next()
554                                            .expect("The bench index should be present")
555                                            .parse::<usize>()
556                                            .expect("The bench index should be a number");
557                                    if key == "setup" {
558                                        $group::__run_bench_setup(group_index, bench_index);
559                                    } else {
560                                        $group::__run_bench_teardown(group_index, bench_index);
561                                    }
562                                }
563                                (name, _) => panic!("Invalid function '{}' in group '{}'", name, group)
564                            }
565                        }
566                    )+
567                    (name, _) => panic!("function '{}' not found in this scope", name)
568                }
569            } else {
570                if let Err(errors) = __run() {
571                    eprintln!("{errors}");
572                    std::process::exit(1);
573                }
574            };
575        }
576    };
577    (
578        $( config = $config:expr; $(;)* )?
579        $( setup = $setup:expr ; $(;)* )?
580        $( teardown = $teardown:expr ; $(;)* )?
581        library_benchmark_groups =
582    ) => {
583        compile_error!("The library_benchmark_groups argument needs at least one `name` of a `library_benchmark_group!`");
584    };
585    (
586        $( config = $config:expr ; $(;)* )?
587        $( setup = $setup:expr ; $(;)* )?
588        $( teardown = $teardown:expr ; $(;)* )?
589        library_benchmark_groups = $( $group:ident ),+ $(,)*
590    ) => {
591        #[inline(never)]
592        fn __run() {
593            let mut this_args = std::env::args();
594            let exe = option_env!("IAI_CALLGRIND_RUNNER")
595                .unwrap_or_else(|| option_env!("CARGO_BIN_EXE_iai-callgrind-runner").unwrap_or("iai-callgrind-runner"));
596
597            let library_version = "0.14.0";
598
599            let mut cmd = std::process::Command::new(exe);
600
601            cmd.arg(library_version);
602            cmd.arg("--lib-bench");
603            cmd.arg(env!("CARGO_MANIFEST_DIR"));
604            cmd.arg(env!("CARGO_PKG_NAME"));
605            cmd.arg(file!());
606            cmd.arg(module_path!());
607            cmd.arg(this_args.next().unwrap()); // The executable benchmark binary
608
609            let mut config: Option<$crate::internal::InternalLibraryBenchmarkConfig> = None;
610            $(
611                config = Some($config.into());
612            )?
613
614            let mut internal_benchmark_groups = $crate::internal::InternalLibraryBenchmarkGroups {
615                config: config.unwrap_or_default(),
616                command_line_args: this_args.collect(),
617                has_setup: __run_setup(false),
618                has_teardown: __run_teardown(false),
619                ..Default::default()
620            };
621
622            $(
623                let mut internal_group = $crate::internal::InternalLibraryBenchmarkGroup {
624                    id: stringify!($group).to_owned(),
625                    config: $group::__get_config(),
626                    compare_by_id: $group::__compare_by_id(),
627                    library_benchmarks: vec![],
628                    has_setup: $group::__run_setup(false),
629                    has_teardown: $group::__run_teardown(false),
630                };
631                for (function_name, get_config, macro_lib_benches) in $group::__BENCHES {
632                    let mut benches = $crate::internal::InternalLibraryBenchmarkBenches {
633                        benches: vec![],
634                        config: get_config()
635                    };
636                    for macro_lib_bench in macro_lib_benches.iter() {
637                        let bench = $crate::internal::InternalLibraryBenchmarkBench {
638                            id: macro_lib_bench.id_display.map(|i| i.to_string()),
639                            args: macro_lib_bench.args_display.map(|i| i.to_string()),
640                            function_name: function_name.to_string(),
641                            config: macro_lib_bench.config.map(|f| f()),
642                        };
643                        benches.benches.push(bench);
644                    }
645                    internal_group.library_benchmarks.push(benches);
646                }
647
648                internal_benchmark_groups.groups.push(internal_group);
649            )+
650
651            let encoded = $crate::bincode::serialize(&internal_benchmark_groups).expect("Encoded benchmark");
652            let mut child = cmd
653                .arg(encoded.len().to_string())
654                .stdin(std::process::Stdio::piped())
655                .spawn()
656                .expect("Failed to run benchmarks. \
657                    Is iai-callgrind-runner installed and iai-callgrind-runner in your $PATH?. \
658                    You can also set the environment variable IAI_CALLGRIND_RUNNER to the \
659                    absolute path of the iai-callgrind-runner executable.");
660
661            let mut stdin = child.stdin.take().expect("Opening stdin to submit encoded benchmark");
662            std::thread::spawn(move || {
663                use std::io::Write;
664                stdin.write_all(&encoded).expect("Writing encoded benchmark to stdin");
665            });
666
667            let status = child.wait().expect("Wait for child process to exit");
668            if !status.success() {
669                std::process::exit(1);
670            }
671        }
672
673        #[inline(never)]
674        fn __run_setup(__run: bool) -> bool {
675            let mut __has_setup = false;
676            $(
677                __has_setup = true;
678                if __run {
679                    $setup;
680                }
681            )?
682            __has_setup
683        }
684
685        #[inline(never)]
686        fn __run_teardown(__run: bool) -> bool {
687            let mut __has_teardown = false;
688            $(
689                __has_teardown = true;
690                if __run {
691                    $teardown;
692                }
693            )?
694            __has_teardown
695        }
696
697        fn main() {
698            let mut args_iter = std::hint::black_box(std::env::args()).skip(1);
699            if args_iter
700                .next()
701                .as_ref()
702                .map_or(false, |value| value == "--iai-run")
703            {
704                let current = std::hint::black_box(args_iter.next().expect("Expecting a function type"));
705                let next = std::hint::black_box(args_iter.next());
706                match current.as_str() {
707                    "setup" if next.is_none() => {
708                        __run_setup(true);
709                    },
710                    "teardown" if next.is_none() => {
711                        __run_teardown(true);
712                    },
713                    $(
714                        stringify!($group) => {
715                            match std::hint::black_box(
716                                next
717                                    .expect("An argument `setup`, `teardown` or an index should be present")
718                                    .as_str()
719                            ) {
720                                "setup" => {
721                                    $group::__run_setup(true);
722                                },
723                                "teardown" => {
724                                    $group::__run_teardown(true);
725                                }
726                                value => {
727                                    let group_index = std::hint::black_box(
728                                        value
729                                            .parse::<usize>()
730                                            .expect("Expecting a valid group index")
731                                    );
732                                    let bench_index = std::hint::black_box(
733                                        args_iter
734                                            .next()
735                                            .expect("A bench index should be present")
736                                            .parse::<usize>()
737                                            .expect("Expecting a valid bench index")
738                                    );
739                                    $group::__run(group_index, bench_index);
740                                }
741                            }
742                        }
743                    )+
744                    name => panic!("function '{}' not found in this scope", name)
745                }
746            } else {
747                std::hint::black_box(__run());
748            };
749        }
750    };
751    (
752        callgrind_args = $( $args:literal ),* $(,)*; $(;)*
753        functions = $( $func_name:ident ),+ $(,)*
754    ) => {
755        compile_error!(
756            "You are using a deprecated syntax of the main! macro to set up library benchmarks. \
757            See the README (https://github.com/iai-callgrind/iai-callgrind) and \
758            docs (https://docs.rs/iai-callgrind/latest/iai_callgrind/) for further details."
759        );
760        pub fn main() {}
761    };
762    ( $( $func_name:ident ),+ $(,)* ) => {
763        compile_error!(
764            "You are using a deprecated syntax of the main! macro to set up library benchmarks. \
765            See the README (https://github.com/iai-callgrind/iai-callgrind) and \
766            docs (https://docs.rs/iai-callgrind/latest/iai_callgrind/) for further details."
767        );
768        pub fn main() {}
769    };
770}
771
772/// Macro used to define a group of binary benchmarks
773///
774/// There are two apis to set up binary benchmarks. The recommended way is to [use the
775/// `#[binary_benchmark]` attribute](#using-the-high-level-api-with-the-binary-benchmark-attribute).
776/// But, if you find yourself in the situation that the attribute isn't enough you can fall back to
777/// the [low level api](#the-low-level-api) or even [intermix both
778/// styles](#intermixing-both-apis).
779///
780/// # The macro's arguments in detail:
781///
782/// The following top-level arguments are accepted (in this order):
783///
784/// ```rust
785/// # use iai_callgrind::{binary_benchmark, binary_benchmark_group, BinaryBenchmarkGroup, BinaryBenchmarkConfig};
786/// # fn run_setup() {}
787/// # fn run_teardown() {}
788/// # #[binary_benchmark]
789/// # fn bench_binary() -> iai_callgrind::Command { iai_callgrind::Command::new("some") }
790/// binary_benchmark_group!(
791///     name = my_group;
792///     config = BinaryBenchmarkConfig::default();
793///     compare_by_id = false;
794///     setup = run_setup();
795///     teardown = run_teardown();
796///     benchmarks = bench_binary
797/// );
798/// # fn main() {
799/// # my_group::my_group(&mut BinaryBenchmarkGroup::default());
800/// # }
801/// ```
802///
803/// * __`name`__ (mandatory): A unique name used to identify the group for the `main!` macro
804/// * __`config`__ (optional): A [`crate::BinaryBenchmarkConfig`]
805/// * __`compare_by_id`__ (optional): The default is false. If true, all commands from the functions
806///   specified in the `benchmarks` argument, are compared with each other as long as the ids (the
807///   part after the `::` in `#[bench::id(...)]`) match.
808/// * __`setup`__ (optional): A function which is executed before all benchmarks in this group
809/// * __`teardown`__ (optional): A function which is executed after all benchmarks in this group
810/// * __`benchmarks`__ (mandatory): A `,`-separated list of `#[binary_benchmark]` annotated function
811///   names you want to put into this group. Or, if you want to use the low level api
812///
813///   `|IDENTIFIER: &mut BinaryBenchmarkGroup| EXPRESSION`
814///
815///   or the shorter `|IDENTIFIER| EXPRESSION`
816///
817///   where `IDENTIFIER` is the identifier of your choice for the `BinaryBenchmarkGroup` (we use
818///   `group` throughout our examples) and `EXPRESSION` is the code where you make use of the
819///   `BinaryBenchmarkGroup` to set up the binary benchmarks
820///
821/// # Using the high-level api with the `#[binary benchmark]` attribute
822///
823/// A small introductory example which demonstrates the basic setup (assuming a crate's binary is
824/// named `my-foo`):
825///
826/// ```rust
827/// # macro_rules! env { ($m:tt) => {{ "/some/path" }} }
828/// use iai_callgrind::{binary_benchmark_group, BinaryBenchmarkGroup, binary_benchmark};
829///
830/// #[binary_benchmark]
831/// #[bench::hello_world("hello world")]
832/// #[bench::foo("foo")]
833/// #[benches::multiple("bar", "baz")]
834/// fn bench_binary(arg: &str) -> iai_callgrind::Command {
835///      iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
836///          .arg(arg)
837///          .build()
838/// }
839///
840/// binary_benchmark_group!(
841///     name = my_group;
842///     benchmarks = bench_binary
843/// );
844///
845/// # fn main() {
846/// iai_callgrind::main!(binary_benchmark_groups = my_group);
847/// # }
848/// ```
849///
850/// To be benchmarked a `binary_benchmark_group` has to be added to the `main!` macro by adding its
851/// name to the `binary_benchmark_groups` argument of the `main!` macro. See there for further
852/// details about the [`crate::main`] macro. See the documentation of [`crate::binary_benchmark`]
853/// for more details about the attribute itself and the inner attributes `#[bench]` and
854/// `#[benches]`.
855///
856/// # The low-level api
857///
858/// Using the low-level api has advantages but when it comes to stability in terms of usability, the
859/// low level api might be considered less stable. What does this mean? If we have to make changes
860/// to the inner workings of iai-callgrind which not necessarily change the high-level api it is
861/// more likely that the low-level api has to be adjusted. This implies you might have to adjust
862/// your benchmarks more often with a version update of `iai-callgrind`. Hence, it is recommended to
863/// use the high-level api as much as possible and only use the low-level api under special
864/// circumstances. You can also [intermix both styles](#intermixing-both-apis)!
865///
866/// The low-level api mirrors the high-level constructs as close as possible. The
867/// [`crate::BinaryBenchmarkGroup`] is a special case, since we use the information from the
868/// `binary_benchmark_group!` macro [arguments](#the-macros-arguments-in-detail) (__`name`__,
869/// __`config`__, ...) to create the `BinaryBenchmarkGroup` and pass it to the `benchmarks`
870/// argument.
871///
872/// That being said, here's the basic usage:
873///
874/// ```rust
875/// # macro_rules! env { ($m:tt) => {{ "/some/path" }} }
876/// use iai_callgrind::{binary_benchmark_group, BinaryBenchmark, Bench};
877///
878/// binary_benchmark_group!(
879///     // All the other options from the `binary_benchmark_group` are used as usual
880///     name = my_group;
881///
882///     // Note there's also the shorter form `benchmarks = |group|` but in the examples we want
883///     // to be more explicit
884///     benchmarks = |group: &mut BinaryBenchmarkGroup| {
885///
886///         // We have chosen `group` to be our identifier but it can be anything
887///         group.binary_benchmark(
888///
889///             // This is the equivalent of the `#[binary_benchmark]` attribute. The `id`
890///             // mirrors the function name of the `#[binary_benchmark]` annotated function.
891///             BinaryBenchmark::new("some_id")
892///                 .bench(
893///
894///                     // The equivalent of the `#[bench]` attribute.
895///                     Bench::new("my_bench_id")
896///                         .command(
897///
898///                             // The `Command` stays the same
899///                             iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
900///                                 .arg("foo").build()
901///                         )
902///                 )
903///         )
904///     }
905/// );
906/// # fn main() {}
907/// ```
908///
909/// Depending on your IDE, it's nicer to work with the code after the `|group: &mut
910/// BinaryBenchmarkGroup|` if it resides in a separate function rather than the macro itself as in
911///
912/// ```rust
913/// use iai_callgrind::{binary_benchmark_group, BinaryBenchmark, Bench, BinaryBenchmarkGroup};
914///
915/// fn setup_my_group(group: &mut BinaryBenchmarkGroup) {
916///     // Enjoy all the features of your IDE ...
917/// }
918///
919/// binary_benchmark_group!(
920///     name = my_group;
921///     benchmarks = |group: &mut BinaryBenchmarkGroup| setup_my_group(group)
922/// );
923/// # fn main() {}
924/// ```
925///
926/// The list of all structs and macros used exclusively in the low-level api:
927/// * [`crate::BinaryBenchmarkGroup`]
928/// * [`crate::BinaryBenchmark`]: Mirrors the `#[binary_benchmark]` attribute
929/// * [`crate::Bench`]: Mirrors the `#[bench]` attribute
930/// * [`crate::binary_benchmark_attribute`]: Used to add a `#[binary_benchmark]` attributed function
931///   in [`crate::BinaryBenchmarkGroup::binary_benchmark`]
932/// * [`crate::BenchmarkId`]: The benchmark id is for example used in
933///   [`crate::BinaryBenchmark::new`] and [`crate::Bench::new`]
934///
935/// Note there's no equivalent for the `#[benches]` attribute. The [`crate::Bench`] behaves exactly
936/// as the `#[benches]` attribute if more than a single [`crate::Command`] is added.
937///
938/// # Intermixing both apis
939///
940/// For example, if you started with the `#[binary_benchmark]` attribute and noticed you are limited
941/// by it to set up all the [`crate::Command`]s the way you want, you can intermix both styles:
942///
943/// ```rust
944/// # macro_rules! env { ($m:tt) => {{ "/some/path" }} }
945/// use iai_callgrind::{
946///     binary_benchmark, binary_benchmark_group, BinaryBenchmark, Bench, BinaryBenchmarkGroup,
947///     binary_benchmark_attribute
948/// };
949///
950/// #[binary_benchmark]
951/// #[bench::foo("foo")]
952/// #[benches::multiple("bar", "baz")]
953/// fn bench_binary(arg: &str) -> iai_callgrind::Command {
954///     iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
955///         .arg(arg)
956///         .build()
957/// }
958///
959/// fn setup_my_group(group: &mut BinaryBenchmarkGroup) {
960///     group
961///         // Simply add what you already have with the `binary_benchmark_attribute!` macro.
962///         // This macro returns a `BinaryBenchmark`, so you could even add more `Bench`es
963///         // to it instead of creating a new one as we do below
964///         .binary_benchmark(binary_benchmark_attribute!(bench_binary))
965///         .binary_benchmark(
966///             BinaryBenchmark::new("did_not_work_with_attribute")
967///                 .bench(Bench::new("low_level")
968///                     .command(
969///                         iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
970///                             .arg("foo")
971///                             .build()
972///                     )
973///                 )
974///         );
975/// }
976///
977/// binary_benchmark_group!(
978///     name = my_group;
979///     benchmarks = |group: &mut BinaryBenchmarkGroup| setup_my_group(group)
980/// );
981/// # fn main() {}
982/// ```
983#[macro_export]
984macro_rules! binary_benchmark_group {
985    (
986        name = $name:ident; $(;)*
987        $(before = $before:ident $(,bench = $bench_before:literal)? ; $(;)*)?
988        $(after = $after:ident $(,bench = $bench_after:literal)? ; $(;)*)?
989        $(setup = $setup:ident $(,bench = $bench_setup:literal)? ; $(;)*)?
990        $(teardown = $teardown:ident $(,bench = $bench_teardown:literal)? ; $(;)*)?
991        $( config = $config:expr ; $(;)* )?
992        benchmark = |$cmd:literal, $group:ident: &mut BinaryBenchmarkGroup| $body:expr
993    ) => {
994        compile_error!(
995            "You are using a deprecated syntax of the binary_benchmark_group! macro to set up binary \
996            benchmarks. See the README (https://github.com/iai-callgrind/iai-callgrind), the \
997            CHANGELOG on the same page and docs (https://docs.rs/iai-callgrind/latest/iai_callgrind) \
998            for further details."
999        );
1000    };
1001    (
1002        name = $name:ident; $(;)*
1003        $( before = $before:ident $(,bench = $bench_before:literal)? ; $(;)* )?
1004        $( after = $after:ident $(,bench = $bench_after:literal)? ; $(;)* )?
1005        $( setup = $setup:ident $(,bench = $bench_setup:literal)? ; $(;)* )?
1006        $( teardown = $teardown:ident $(,bench = $bench_teardown:literal )? ; $(;)* )?
1007        $( config = $config:expr ; $(;)* )?
1008        benchmark = |$group:ident: &mut BinaryBenchmarkGroup| $body:expr
1009    ) => {
1010        compile_error!(
1011            "You are using a deprecated syntax of the binary_benchmark_group! macro to set up binary \
1012            benchmarks. See the README (https://github.com/iai-callgrind/iai-callgrind), the \
1013            CHANGELOG on the same page and docs (https://docs.rs/iai-callgrind/latest/iai_callgrind) \
1014            for further details."
1015        );
1016    };
1017    (
1018        $( config = $config:expr ; $(;)* )?
1019        $( compare_by_id = $compare:literal ; $(;)* )?
1020        $( setup = $setup:expr; $(;)* )?
1021        $( teardown = $teardown:expr; $(;)* )?
1022        benchmarks = $( $function:ident ),+ $(,)*
1023    ) => {
1024        compile_error!(
1025            "A binary_benchmark_group! needs a unique name. See the documentation of this macro for \
1026            further details.\n\n\
1027            hint = binary_benchmark_group!(name = some_ident; benchmarks = some_binary_benchmark);"
1028        );
1029    };
1030    (
1031        name = $name:ident; $(;)*
1032        $( config = $config:expr; $(;)* )?
1033        $( compare_by_id = $compare:literal; $(;)* )?
1034        $( setup = $setup:expr; $(;)* )?
1035        $( teardown = $teardown:expr; $(;)* )?
1036        benchmarks =
1037    ) => {
1038        compile_error!(
1039            "A binary_benchmark_group! needs at least 1 benchmark function which is annotated with \
1040            #[binary_benchmark] or you can use the low level syntax. See the documentation of this \
1041            macro for further details.\n\n\
1042            hint = binary_benchmark_group!(name = some_ident; benchmarks = some_binary_benchmark);"
1043        );
1044    };
1045    (
1046        name = $name:ident; $(;)*
1047        $( config = $config:expr ; $(;)* )?
1048        $( compare_by_id = $compare:literal ; $(;)* )?
1049        $( setup = $setup:expr; $(;)* )?
1050        $( teardown = $teardown:expr; $(;)* )?
1051    ) => {
1052        compile_error!(
1053            "A binary_benchmark_group! needs at least 1 benchmark function which is annotated with \
1054            #[binary_benchmark] or you can use the low level syntax. See the documentation of this \
1055            macro for further details.\n\n\
1056            hint = binary_benchmark_group!(name = some_ident; benchmarks = some_binary_benchmark);"
1057        );
1058    };
1059    (
1060        name = $name:ident; $(;)*
1061        $( config = $config:expr ; $(;)* )?
1062        $( compare_by_id = $compare:literal ; $(;)* )?
1063        $( setup = $setup:expr; $(;)* )?
1064        $( teardown = $teardown:expr; $(;)* )?
1065        benchmarks = $( $function:ident ),+ $(,)*
1066    ) => {
1067        pub mod $name {
1068            use super::*;
1069
1070            pub const __IS_ATTRIBUTE: bool = true;
1071
1072            pub const __BENCHES: &[&(
1073                &'static str,
1074                fn() -> Option<$crate::internal::InternalBinaryBenchmarkConfig>,
1075                &[$crate::internal::InternalMacroBinBench]
1076            )]= &[
1077                $(
1078                    &(
1079                        stringify!($function),
1080                        super::$function::__get_config,
1081                        super::$function::__BENCHES
1082                    )
1083                ),+
1084            ];
1085
1086            pub fn __run_setup(__run: bool) -> bool {
1087                let mut __has_setup = false;
1088                $(
1089                    __has_setup = true;
1090                    if __run {
1091                        $setup;
1092                    }
1093                )?
1094                __has_setup
1095            }
1096
1097            pub fn __run_teardown(__run: bool) -> bool {
1098                let mut __has_teardown = false;
1099                $(
1100                    __has_teardown = true;
1101                    if __run {
1102                        $teardown;
1103                    }
1104                )?
1105                __has_teardown
1106            }
1107
1108            pub fn __compare_by_id() -> Option<bool> {
1109                let mut comp = None;
1110                $(
1111                    comp = Some($compare);
1112                )?
1113                comp
1114            }
1115
1116            pub fn __get_config() -> Option<$crate::internal::InternalBinaryBenchmarkConfig> {
1117                let mut config = None;
1118                $(
1119                    config = Some($config.into());
1120                )?
1121                config
1122            }
1123
1124            pub fn __run_bench_setup(group_index: usize, bench_index: usize) {
1125                if let Some(setup) = __BENCHES[group_index].2[bench_index].setup {
1126                    setup();
1127                };
1128            }
1129
1130            pub fn __run_bench_teardown(group_index: usize, bench_index: usize) {
1131                if let Some(teardown) = __BENCHES[group_index].2[bench_index].teardown {
1132                    teardown();
1133                };
1134            }
1135
1136            pub fn $name(_: &mut $crate::BinaryBenchmarkGroup) {}
1137        }
1138    };
1139    (
1140        $( config = $config:expr; $(;)* )?
1141        $( compare_by_id = $compare:literal ; $(;)* )?
1142        $( setup = $setup:expr; $(;)* )?
1143        $( teardown = $teardown:expr; $(;)* )?
1144        benchmarks = |$group:ident: &mut BinaryBenchmarkGroup| $body:expr
1145    ) => {
1146        compile_error!(
1147            "A binary_benchmark_group! needs a unique name. See the documentation of this macro for \
1148            further details.\n\n\
1149            hint = binary_benchmark_group!(name = some_ident; benchmarks = |group: &mut BinaryBenchmarkGroup| ... );"
1150        );
1151    };
1152    (
1153        $( config = $config:expr; $(;)* )?
1154        $( compare_by_id = $compare:literal ; $(;)* )?
1155        $( setup = $setup:expr; $(;)* )?
1156        $( teardown = $teardown:expr; $(;)* )?
1157        benchmarks = |$group:ident| $body:expr
1158    ) => {
1159        compile_error!(
1160            "A binary_benchmark_group! needs a unique name. See the documentation of this macro for \
1161            further details.\n\n\
1162            hint = binary_benchmark_group!(name = some_ident; benchmarks = |group| ... );"
1163        );
1164    };
1165    (
1166        name = $name:ident; $(;)*
1167        $( config = $config:expr; $(;)* )?
1168        $( compare_by_id = $compare:literal ; $(;)* )?
1169        $( setup = $setup:expr; $(;)* )?
1170        $( teardown = $teardown:expr; $(;)* )?
1171        benchmarks = |$group:ident|
1172    ) => {
1173        compile_error!(
1174            "This low level form of the binary_benchmark_group! needs you to use the \
1175            `BinaryBenchmarkGroup` to setup benchmarks. See the documentation of this macro for \
1176            further details.\n\n\
1177            hint = binary_benchmark_group!(name = some_ident; benchmarks = |group| { \
1178                group.binary_benchmark(/* BinaryBenchmark::new */); });"
1179        );
1180    };
1181    (
1182        name = $name:ident; $(;)*
1183        $( config = $config:expr; $(;)* )?
1184        $( compare_by_id = $compare:literal ; $(;)* )?
1185        $( setup = $setup:expr; $(;)* )?
1186        $( teardown = $teardown:expr; $(;)* )?
1187        benchmarks = |$group:ident: &mut BinaryBenchmarkGroup|
1188    ) => {
1189        compile_error!(
1190            "This low level form of the binary_benchmark_group! needs you to use the \
1191            `BinaryBenchmarkGroup` to setup benchmarks. See the documentation of this macro for \
1192            further details.\n\n\
1193            hint = binary_benchmark_group!(name = some_ident; benchmarks = |group: &mut \
1194                BinaryBenchmarkGroup| { group.binary_benchmark(/* BinaryBenchmark::new */); });"
1195        );
1196    };
1197    (
1198        name = $name:ident; $(;)*
1199        $( config = $config:expr; $(;)* )?
1200        $( compare_by_id = $compare:literal ; $(;)* )?
1201        $( setup = $setup:expr; $(;)* )?
1202        $( teardown = $teardown:expr; $(;)* )?
1203        benchmarks = |$group:ident: &mut BinaryBenchmarkGroup| $body:expr
1204    ) => {
1205        pub mod $name {
1206            use super::*;
1207
1208            pub const __IS_ATTRIBUTE: bool = false;
1209
1210            pub const __BENCHES: &[&(
1211                &'static str,
1212                fn() -> Option<$crate::internal::InternalBinaryBenchmarkConfig>,
1213                &[$crate::internal::InternalMacroBinBench]
1214            )]= &[];
1215
1216            pub fn __run_setup(__run: bool) -> bool {
1217                let mut __has_setup = false;
1218                $(
1219                    __has_setup = true;
1220                    if __run {
1221                        $setup;
1222                    }
1223                )?
1224                __has_setup
1225            }
1226
1227            pub fn __run_teardown(__run: bool) -> bool {
1228                let mut __has_teardown = false;
1229                $(
1230                    __has_teardown = true;
1231                    if __run {
1232                        $teardown;
1233                    }
1234                )?
1235                __has_teardown
1236            }
1237
1238            pub fn __get_config() -> Option<$crate::internal::InternalBinaryBenchmarkConfig> {
1239                let mut config = None;
1240                $(
1241                    config = Some($config.into());
1242                )?
1243                config
1244            }
1245
1246            pub fn __compare_by_id() -> Option<bool> {
1247                let mut comp = None;
1248                $(
1249                    comp = Some($compare);
1250                )?
1251                comp
1252            }
1253
1254            pub fn __run_bench_setup(group_index: usize, bench_index: usize) {
1255                let mut group = $crate::BinaryBenchmarkGroup::default();
1256                $name(&mut group);
1257
1258                let bench = group
1259                    .binary_benchmarks
1260                    .iter()
1261                    .nth(group_index)
1262                    .expect("The group index for setup should be present");
1263                // In the runner each command is a `BinBench` and it is the index of the command
1264                // which we're getting back from the runner. So, we have to iterate over the
1265                // commands of each Bench to extract the correct setup function.
1266                //
1267                // commands                           => bench_index => The correct setup function
1268                // bench.benches[0].commands = [a, b] => 0, 1        => bench.benches[0].setup
1269                // bench.benches[1].commands = [c]    => 2           => bench.benches[1].setup
1270                // bench.benches[2].commands = [d, e] => 3, 4        => bench.benches[2].setup
1271                //
1272                // We also need to take care of that there can be a global setup function
1273                // `BinaryBenchmark::setup`, which can be overridden by a `Bench::setup`
1274                if let Some(setup) = bench
1275                        .benches
1276                        .iter()
1277                        .flat_map(|b| b.commands.iter().map(|c| (b.setup, c)))
1278                        .nth(bench_index)
1279                        .map(|(setup, _)| setup)
1280                        .expect("The bench index for setup should be present") {
1281                    setup();
1282                } else if let Some(setup) = bench.setup {
1283                    setup();
1284                } else {
1285                    // This branch should be unreachable so we do nothing
1286                }
1287            }
1288
1289            pub fn __run_bench_teardown(group_index: usize, bench_index: usize) {
1290                let mut group = $crate::BinaryBenchmarkGroup::default();
1291                $name(&mut group);
1292
1293                let bench = group
1294                    .binary_benchmarks
1295                    .iter()
1296                    .nth(group_index)
1297                    .expect("The group index for teardown should be present");
1298                if let Some(teardown) = bench
1299                        .benches
1300                        .iter()
1301                        .flat_map(|b| b.commands.iter().map(|c| (b.teardown, c)))
1302                        .nth(bench_index)
1303                        .map(|(teardown, _)| teardown)
1304                        .expect("The bench index for teardown should be present") {
1305                    teardown();
1306                } else if let Some(teardown) = bench.teardown {
1307                    teardown();
1308                } else {
1309                    // This branch should be unreachable so we do nothing
1310                }
1311            }
1312
1313            #[inline(never)]
1314            pub fn $name($group: &mut $crate::BinaryBenchmarkGroup) {
1315                $body;
1316            }
1317        }
1318    };
1319    (
1320        name = $name:ident; $(;)*
1321        $( config = $config:expr; $(;)* )?
1322        $( compare_by_id = $compare:literal ; $(;)* )?
1323        $( setup = $setup:expr; $(;)* )?
1324        $( teardown = $teardown:expr; $(;)* )?
1325        benchmarks = |$group:ident| $body:expr
1326    ) => {
1327        binary_benchmark_group!(
1328            name = $name;
1329            $( config = $config; )?
1330            $( compare_by_id = $compare; )?
1331            $( setup = $setup; )?
1332            $( teardown = $teardown; )?
1333            benchmarks = |$group: &mut BinaryBenchmarkGroup| $body
1334        );
1335    };
1336}
1337
1338/// Macro used to define a group of library benchmarks
1339///
1340/// A small introductory example which shows the basic setup. This macro only accepts benchmarks
1341/// annotated with `#[library_benchmark]` ([`crate::library_benchmark`]).
1342///
1343/// ```rust
1344/// use iai_callgrind::{library_benchmark_group, library_benchmark};
1345///
1346/// #[library_benchmark]
1347/// fn bench_something() -> u64 {
1348///     42
1349/// }
1350///
1351/// library_benchmark_group!(
1352///     name = my_group;
1353///     benchmarks = bench_something
1354/// );
1355///
1356/// # fn main() {
1357/// iai_callgrind::main!(library_benchmark_groups = my_group);
1358/// # }
1359/// ```
1360///
1361/// To be benchmarked a `library_benchmark_group` has to be added to the `main!` macro by adding its
1362/// name to the `library_benchmark_groups` argument of the `main!` macro. See there for further
1363/// details about the [`crate::main`] macro.
1364///
1365/// The following top-level arguments are accepted in this order:
1366///
1367/// ```rust
1368/// # use iai_callgrind::{library_benchmark, library_benchmark_group, LibraryBenchmarkConfig};
1369/// # #[library_benchmark]
1370/// # fn some_func() {}
1371/// fn group_setup() {}
1372/// fn group_teardown() {}
1373/// library_benchmark_group!(
1374///     name = my_group;
1375///     config = LibraryBenchmarkConfig::default();
1376///     compare_by_id = false;
1377///     setup = group_setup();
1378///     teardown = group_teardown();
1379///     benchmarks = some_func
1380/// );
1381/// # fn main() {
1382/// # }
1383/// ```
1384///
1385/// * __`name`__ (mandatory): A unique name used to identify the group for the `main!` macro
1386/// * __`config`__ (optional): A [`crate::LibraryBenchmarkConfig`] which is applied to all
1387///   benchmarks within the same group.
1388/// * __`compare_by_id`__ (optional): The default is false. If true, all benches in the benchmark
1389///   functions specified with the `benchmarks` argument, across any benchmark groups, are compared
1390///   with each other as long as the ids (the part after the `::` in `#[bench::id(...)]`) match.
1391/// * __`setup`__ (optional): A setup function or any valid expression which is run before all
1392///   benchmarks of this group
1393/// * __`teardown`__ (optional): A teardown function or any valid expression which is run after all
1394///   benchmarks of this group
1395/// * __`benchmarks`__ (mandatory): A list of comma separated benchmark functions which must be
1396///   annotated with `#[library_benchmark]`
1397#[macro_export]
1398macro_rules! library_benchmark_group {
1399    (
1400        $( config = $config:expr ; $(;)* )?
1401        $( compare_by_id = $compare:literal ; $(;)* )?
1402        $( setup = $setup:expr ; $(;)* )?
1403        $( teardown = $teardown:expr ; $(;)* )?
1404        benchmarks = $( $function:ident ),+
1405    ) => {
1406        compile_error!("A library_benchmark_group! needs a name\n\nlibrary_benchmark_group!(name = some_ident; benchmarks = ...);");
1407    };
1408    (
1409        name = $name:ident;
1410        $( config = $config:expr ; $(;)* )?
1411        $( compare_by_id = $compare:literal ; $(;)* )?
1412        $( setup = $setup:expr ; $(;)* )?
1413        $( teardown = $teardown:expr ; $(;)* )?
1414        benchmarks =
1415    ) => {
1416        compile_error!(
1417            "A library_benchmark_group! needs at least 1 benchmark function \
1418            annotated with #[library_benchmark]\n\n\
1419            library_benchmark_group!(name = some_ident; benchmarks = some_library_benchmark);");
1420    };
1421    (
1422        name = $name:ident; $(;)*
1423        $( config = $config:expr ; $(;)* )?
1424        $( compare_by_id = $compare:literal ; $(;)* )?
1425        $( setup = $setup:expr ; $(;)* )?
1426        $( teardown = $teardown:expr ; $(;)* )?
1427        benchmarks = $( $function:ident ),+ $(,)*
1428    ) => {
1429        pub mod $name {
1430            use super::*;
1431
1432            pub const __BENCHES: &[&(
1433                &'static str,
1434                fn() -> Option<$crate::internal::InternalLibraryBenchmarkConfig>,
1435                &[$crate::internal::InternalMacroLibBench]
1436            )]= &[
1437                $(
1438                    &(
1439                        stringify!($function),
1440                        super::$function::__get_config,
1441                        super::$function::__BENCHES
1442                    )
1443                ),+
1444            ];
1445
1446            #[inline(never)]
1447            pub fn __get_config() -> Option<$crate::internal::InternalLibraryBenchmarkConfig> {
1448                let mut config: Option<$crate::internal::InternalLibraryBenchmarkConfig> = None;
1449                $(
1450                    config = Some($config.into());
1451                )?
1452                config
1453            }
1454
1455            #[inline(never)]
1456            pub fn __compare_by_id() -> Option<bool> {
1457                let mut comp = None;
1458                $(
1459                    comp = Some($compare);
1460                )?
1461                comp
1462            }
1463
1464            #[inline(never)]
1465            pub fn __run_setup(__run: bool) -> bool {
1466                let mut __has_setup = false;
1467                $(
1468                    __has_setup = true;
1469                    if __run {
1470                        $setup;
1471                    }
1472                )?
1473                __has_setup
1474            }
1475
1476            #[inline(never)]
1477            pub fn __run_teardown(__run: bool) -> bool {
1478                let mut __has_teardown = false;
1479                $(
1480                    __has_teardown = true;
1481                    if __run {
1482                        $teardown;
1483                    }
1484                )?
1485                __has_teardown
1486            }
1487
1488            #[inline(never)]
1489            pub fn __run(group_index: usize, bench_index: usize) {
1490                (__BENCHES[group_index].2[bench_index].func)();
1491            }
1492        }
1493    };
1494}