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#[derive(Clone, Debug, Default, Parser)]
15#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
16pub struct BenchOptions {
17 #[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 #[arg(long, help_heading = heading::PACKAGE_SELECTION)]
31 #[cfg_attr(feature = "serde", serde(default))]
32 pub workspace: bool,
33
34 #[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 #[arg(long, help_heading = heading::PACKAGE_SELECTION,)]
46 #[cfg_attr(feature = "serde", serde(default))]
47 pub all: bool,
48
49 #[arg(long, help_heading = heading::TARGET_SELECTION)]
51 #[cfg_attr(feature = "serde", serde(default))]
52 pub lib: bool,
53
54 #[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 #[arg(long, help_heading = heading::TARGET_SELECTION)]
67 #[cfg_attr(feature = "serde", serde(default))]
68 pub bins: bool,
69
70 #[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 #[arg(long, help_heading = heading::TARGET_SELECTION)]
83 #[cfg_attr(feature = "serde", serde(default))]
84 pub examples: bool,
85
86 #[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 #[arg(long, help_heading = heading::TARGET_SELECTION)]
98 #[cfg_attr(feature = "serde", serde(default))]
99 pub tests: bool,
100
101 #[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 #[arg(long, help_heading = heading::TARGET_SELECTION)]
113 #[cfg_attr(feature = "serde", serde(default))]
114 pub benches: bool,
115
116 #[arg(long, help_heading = heading::TARGET_SELECTION)]
118 #[cfg_attr(feature = "serde", serde(default))]
119 pub all_targets: bool,
120
121 #[arg(long)]
123 #[cfg_attr(feature = "serde", serde(default))]
124 pub no_run: bool,
125
126 #[arg(long)]
128 #[cfg_attr(feature = "serde", serde(default))]
129 pub no_fail_fast: bool,
130
131 #[arg(value_name = "BENCHNAME")]
133 #[cfg_attr(feature = "serde", serde(default))]
134 pub bench_name: Option<String>,
135
136 #[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#[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 #[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 #[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
226 #[cfg_attr(feature = "serde", serde(default))]
227 pub ignore_rust_version: bool,
228
229 #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
231 #[cfg_attr(feature = "serde", serde(default))]
232 pub unit_graph: bool,
233}
234
235impl Bench {
236 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}