Skip to content

Commit 1cee9c8

Browse files
committed
Simplify Scenario and Profile parsers
Also removes the `possible_values` implementation. It wasn't used by Clap anyway.
1 parent af47db7 commit 1cee9c8

File tree

1 file changed

+23
-61
lines changed

1 file changed

+23
-61
lines changed

collector/src/bin/collector.rs

+23-61
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#![recursion_limit = "1024"]
22

33
use anyhow::Context;
4-
use clap::builder::{PossibleValue, TypedValueParser};
5-
use clap::{Arg, Parser, ValueEnum};
4+
use clap::builder::TypedValueParser;
5+
use clap::{Arg, Parser};
66
use collector::api::next_artifact::NextArtifact;
77
use collector::codegen::{codegen_diff, CodegenType};
88
use collector::compile::benchmark::category::Category;
@@ -22,6 +22,7 @@ use std::fs::File;
2222
use std::future::Future;
2323
use std::io::BufWriter;
2424
use std::io::Write;
25+
use std::marker::PhantomData;
2526
use std::path::{Path, PathBuf};
2627
use std::process;
2728
use std::process::Command;
@@ -230,55 +231,24 @@ fn main() {
230231
}
231232
}
232233

233-
#[derive(Debug, Clone)]
234-
struct ProfileArg(Vec<Profile>);
234+
/// We need to have a separate wrapper over a Vec<T>, otherwise Clap would incorrectly
235+
/// assume that `EnumArgParser` parses a single item, rather than a list of items.
236+
#[derive(Clone, Debug)]
237+
struct MultiEnumValue<T>(Vec<T>);
235238

239+
/// Parser for enums (like profile or scenario) which can be passed either as a comma-delimited
240+
/// string or as the "All" string, which selects all variants.
236241
#[derive(Clone)]
237-
struct ProfileArgParser;
242+
struct EnumArgParser<T>(PhantomData<T>);
238243

239-
/// We need to use a TypedValueParser to provide possible values help.
240-
/// If we just use `FromStr` + `#[arg(possible_values = [...])]`, `clap` will not allow passing
241-
/// multiple values.
242-
impl TypedValueParser for ProfileArgParser {
243-
type Value = ProfileArg;
244-
245-
fn parse_ref(
246-
&self,
247-
cmd: &clap::Command,
248-
arg: Option<&Arg>,
249-
value: &OsStr,
250-
) -> Result<Self::Value, clap::Error> {
251-
if value == "All" {
252-
Ok(ProfileArg(Profile::all()))
253-
} else {
254-
let profiles: Result<Vec<Profile>, _> = value
255-
.to_str()
256-
.unwrap()
257-
.split(',')
258-
.map(|item| clap::value_parser!(Profile).parse_ref(cmd, arg, OsStr::new(item)))
259-
.collect();
260-
261-
Ok(ProfileArg(profiles?))
262-
}
263-
}
264-
265-
fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
266-
let values = Profile::value_variants()
267-
.iter()
268-
.filter_map(|item| item.to_possible_value())
269-
.chain([PossibleValue::new("All")]);
270-
Some(Box::new(values))
244+
impl<T> Default for EnumArgParser<T> {
245+
fn default() -> Self {
246+
Self(Default::default())
271247
}
272248
}
273249

274-
#[derive(Debug, Clone)]
275-
struct ScenarioArg(Vec<Scenario>);
276-
277-
#[derive(Clone)]
278-
struct ScenarioArgParser;
279-
280-
impl TypedValueParser for ScenarioArgParser {
281-
type Value = ScenarioArg;
250+
impl<T: clap::ValueEnum + Sync + Send + 'static> TypedValueParser for EnumArgParser<T> {
251+
type Value = MultiEnumValue<T>;
282252

283253
fn parse_ref(
284254
&self,
@@ -287,26 +257,18 @@ impl TypedValueParser for ScenarioArgParser {
287257
value: &OsStr,
288258
) -> Result<Self::Value, clap::Error> {
289259
if value == "All" {
290-
Ok(ScenarioArg(Scenario::all()))
260+
Ok(MultiEnumValue(T::value_variants().to_vec()))
291261
} else {
292-
let scenarios: Result<Vec<Scenario>, _> = value
262+
let values: Result<Vec<T>, _> = value
293263
.to_str()
294264
.unwrap()
295265
.split(',')
296-
.map(|item| clap::value_parser!(Scenario).parse_ref(cmd, arg, OsStr::new(item)))
266+
.map(|item| clap::value_parser!(T).parse_ref(cmd, arg, OsStr::new(item)))
297267
.collect();
298268

299-
Ok(ScenarioArg(scenarios?))
269+
Ok(MultiEnumValue(values?))
300270
}
301271
}
302-
303-
fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
304-
let values = Scenario::value_variants()
305-
.iter()
306-
.filter_map(|item| item.to_possible_value())
307-
.chain([PossibleValue::new("All")]);
308-
Some(Box::new(values))
309-
}
310272
}
311273

312274
#[derive(Debug, clap::Parser)]
@@ -358,20 +320,20 @@ struct CompileTimeOptions {
358320
#[arg(
359321
long = "profiles",
360322
alias = "builds", // the old name, for backward compatibility
361-
value_parser = ProfileArgParser,
323+
value_parser = EnumArgParser::<Profile>::default(),
362324
// Don't run rustdoc by default
363325
default_value = "Check,Debug,Opt",
364326
)]
365-
profiles: ProfileArg,
327+
profiles: MultiEnumValue<Profile>,
366328

367329
/// Measure the scenarios in this comma-separated list
368330
#[arg(
369331
long = "scenarios",
370332
alias = "runs", // the old name, for backward compatibility
371-
value_parser = ScenarioArgParser,
333+
value_parser = EnumArgParser::<Scenario>::default(),
372334
default_value = "All"
373335
)]
374-
scenarios: ScenarioArg,
336+
scenarios: MultiEnumValue<Scenario>,
375337

376338
/// The path to the local rustdoc to measure
377339
#[arg(long)]

0 commit comments

Comments
 (0)