Skip to main content

cargo_options/
bench.rs

1use std::ops::{Deref, DerefMut};
2use std::path::PathBuf;
3use std::process::Command;
4
5use clap::{ArgAction, Parser};
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::common::CommonOptions;
11use crate::heading;
12
13/// `cargo bench` options
14#[derive(Clone, Debug, Default, Parser)]
15#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
16pub struct BenchOptions {
17    /// Package to run benchmarks for
18    #[arg(
19        short = 'p',
20        long = "package",
21        value_name = "SPEC",
22        action = ArgAction::Append,
23        num_args=0..=1,
24        help_heading = heading::PACKAGE_SELECTION,
25    )]
26    #[cfg_attr(feature = "serde", serde(default))]
27    pub packages: Vec<String>,
28
29    /// Benchmark all packages in the workspace
30    #[arg(long, help_heading = heading::PACKAGE_SELECTION)]
31    #[cfg_attr(feature = "serde", serde(default))]
32    pub workspace: bool,
33
34    /// Exclude packages from the benchmark
35    #[arg(
36        long,
37        value_name = "SPEC",
38        action = ArgAction::Append,
39        help_heading = heading::PACKAGE_SELECTION,
40    )]
41    #[cfg_attr(feature = "serde", serde(default))]
42    pub exclude: Vec<String>,
43
44    /// Alias for --workspace (deprecated)
45    #[arg(long, help_heading = heading::PACKAGE_SELECTION,)]
46    #[cfg_attr(feature = "serde", serde(default))]
47    pub all: bool,
48
49    /// Benchmark only this package's library
50    #[arg(long, help_heading = heading::TARGET_SELECTION)]
51    #[cfg_attr(feature = "serde", serde(default))]
52    pub lib: bool,
53
54    /// Benchmark only the specified binary
55    #[arg(
56        long,
57        value_name = "NAME",
58        action = ArgAction::Append,
59        num_args=0..=1,
60        help_heading = heading::TARGET_SELECTION,
61    )]
62    #[cfg_attr(feature = "serde", serde(default))]
63    pub bin: Vec<String>,
64
65    /// Benchmark all binaries
66    #[arg(long, help_heading = heading::TARGET_SELECTION)]
67    #[cfg_attr(feature = "serde", serde(default))]
68    pub bins: bool,
69
70    /// Benchmark only the specified example
71    #[arg(
72        long,
73        value_name = "NAME",
74        action = ArgAction::Append,
75        num_args=0..=1,
76        help_heading = heading::TARGET_SELECTION,
77    )]
78    #[cfg_attr(feature = "serde", serde(default))]
79    pub example: Vec<String>,
80
81    /// Benchmark all examples
82    #[arg(long, help_heading = heading::TARGET_SELECTION)]
83    #[cfg_attr(feature = "serde", serde(default))]
84    pub examples: bool,
85
86    /// Benchmark only the specified test target
87    #[arg(
88        long,
89        value_name = "NAME",
90        action = ArgAction::Append,
91        help_heading = heading::TARGET_SELECTION,
92    )]
93    #[cfg_attr(feature = "serde", serde(default))]
94    pub test: Vec<String>,
95
96    /// Benchmark all targets that have `test = true` set
97    #[arg(long, help_heading = heading::TARGET_SELECTION)]
98    #[cfg_attr(feature = "serde", serde(default))]
99    pub tests: bool,
100
101    /// Benchmark only the specified bench target
102    #[arg(
103        long,
104        value_name = "NAME",
105        action = ArgAction::Append,
106        help_heading = heading::TARGET_SELECTION,
107    )]
108    #[cfg_attr(feature = "serde", serde(default))]
109    pub bench: Vec<String>,
110
111    /// Benchmark all targets that have `bench = true` set
112    #[arg(long, help_heading = heading::TARGET_SELECTION)]
113    #[cfg_attr(feature = "serde", serde(default))]
114    pub benches: bool,
115
116    /// Benchmark all targets
117    #[arg(long, help_heading = heading::TARGET_SELECTION)]
118    #[cfg_attr(feature = "serde", serde(default))]
119    pub all_targets: bool,
120
121    /// Compile, but don't run benchmarks
122    #[arg(long)]
123    #[cfg_attr(feature = "serde", serde(default))]
124    pub no_run: bool,
125
126    /// Run all benchmarks regardless of failure
127    #[arg(long)]
128    #[cfg_attr(feature = "serde", serde(default))]
129    pub no_fail_fast: bool,
130
131    /// If specified, only run benches containing this string in their names
132    #[arg(value_name = "BENCHNAME")]
133    #[cfg_attr(feature = "serde", serde(default))]
134    pub bench_name: Option<String>,
135
136    /// Arguments for the bench binary
137    #[arg(value_name = "ARGS", last = true, num_args = 0..)]
138    #[cfg_attr(feature = "serde", serde(default))]
139    pub args: Vec<String>,
140}
141
142impl BenchOptions {
143    pub fn apply(&self, cmd: &mut Command) {
144        for pkg in &self.packages {
145            cmd.arg("--package").arg(pkg);
146        }
147        if self.workspace {
148            cmd.arg("--workspace");
149        }
150        for item in &self.exclude {
151            cmd.arg("--exclude").arg(item);
152        }
153        if self.all {
154            cmd.arg("--all");
155        }
156        if self.lib {
157            cmd.arg("--lib");
158        }
159        for bin in &self.bin {
160            cmd.arg("--bin").arg(bin);
161        }
162        if self.bins {
163            cmd.arg("--bins");
164        }
165        for example in &self.example {
166            cmd.arg("--example").arg(example);
167        }
168        if self.examples {
169            cmd.arg("--examples");
170        }
171        for test in &self.test {
172            cmd.arg("--test").arg(test);
173        }
174        if self.tests {
175            cmd.arg("--tests");
176        }
177        for bench in &self.bench {
178            cmd.arg("--bench").arg(bench);
179        }
180        if self.benches {
181            cmd.arg("--benches");
182        }
183        if self.all_targets {
184            cmd.arg("--all-targets");
185        }
186        if self.no_run {
187            cmd.arg("--no-run");
188        }
189        if self.no_fail_fast {
190            cmd.arg("--no-fail-fast");
191        }
192        if self.bench_name.is_some() || !self.args.is_empty() {
193            cmd.arg("--");
194            if let Some(bench_name) = self.bench_name.as_ref() {
195                cmd.arg(bench_name);
196            }
197        }
198        cmd.args(&self.args);
199    }
200}
201
202/// Execute all benchmarks of a local package
203#[derive(Clone, Debug, Default, Parser)]
204#[command(
205    display_order = 1,
206    after_help = "Run `cargo help bench` for more detailed information."
207)]
208#[group(skip)]
209#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
210pub struct Bench {
211    #[command(flatten)]
212    #[cfg_attr(feature = "serde", serde(flatten))]
213    pub common: CommonOptions,
214
215    #[command(flatten)]
216    #[cfg_attr(feature = "serde", serde(flatten))]
217    pub bench: BenchOptions,
218
219    /// Path to Cargo.toml
220    #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)]
221    #[cfg_attr(feature = "serde", serde(default))]
222    pub manifest_path: Option<PathBuf>,
223
224    /// Ignore `rust-version` specification in packages
225    #[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
226    #[cfg_attr(feature = "serde", serde(default))]
227    pub ignore_rust_version: bool,
228
229    /// Output build graph in JSON (unstable)
230    #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
231    #[cfg_attr(feature = "serde", serde(default))]
232    pub unit_graph: bool,
233}
234
235impl Bench {
236    /// Build a `cargo bench` command
237    pub fn command(&self) -> Command {
238        let mut cmd = CommonOptions::cargo_command();
239        cmd.arg("bench");
240
241        self.common.apply(&mut cmd);
242        self.bench.apply(&mut cmd);
243
244        if let Some(path) = self.manifest_path.as_ref() {
245            cmd.arg("--manifest-path").arg(path);
246        }
247        if self.ignore_rust_version {
248            cmd.arg("--ignore-rust-version");
249        }
250        if self.unit_graph {
251            cmd.arg("--unit-graph");
252        }
253
254        cmd
255    }
256}
257
258impl Deref for Bench {
259    type Target = CommonOptions;
260
261    fn deref(&self) -> &Self::Target {
262        &self.common
263    }
264}
265
266impl DerefMut for Bench {
267    fn deref_mut(&mut self) -> &mut Self::Target {
268        &mut self.common
269    }
270}
271
272#[cfg(test)]
273mod test {
274    use super::Bench;
275    use clap::CommandFactory;
276
277    #[test]
278    fn verify_cli() {
279        <Bench as CommandFactory>::command().debug_assert()
280    }
281}