11#![ recursion_limit = "1024" ]
22
33use anyhow:: Context ;
4- use clap:: builder:: { PossibleValue , TypedValueParser } ;
5- use clap:: { Arg , Parser , ValueEnum } ;
4+ use clap:: builder:: TypedValueParser ;
5+ use clap:: { Arg , Parser } ;
66use collector:: api:: next_artifact:: NextArtifact ;
77use collector:: codegen:: { codegen_diff, CodegenType } ;
88use collector:: compile:: benchmark:: category:: Category ;
@@ -22,6 +22,7 @@ use std::fs::File;
2222use std:: future:: Future ;
2323use std:: io:: BufWriter ;
2424use std:: io:: Write ;
25+ use std:: marker:: PhantomData ;
2526use std:: path:: { Path , PathBuf } ;
2627use std:: process;
2728use 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