xref: /third_party/rust/crates/clap/src/derive.rs (revision 19625d8c)
1//! This module contains traits that are usable with the `#[derive(...)].`
2//! macros in [`clap_derive`].
3
4use crate::builder::PossibleValue;
5use crate::{ArgMatches, Command, Error};
6
7use std::ffi::OsString;
8
9/// Parse command-line arguments into `Self`.
10///
11/// The primary one-stop-shop trait used to create an instance of a `clap`
12/// [`Command`], conduct the parsing, and turn the resulting [`ArgMatches`] back
13/// into concrete instance of the user struct.
14///
15/// This trait is primarily a convenience on top of [`FromArgMatches`] +
16/// [`CommandFactory`] which uses those two underlying traits to build the two
17/// fundamental functions `parse` which uses the `std::env::args_os` iterator,
18/// and `parse_from` which allows the consumer to supply the iterator (along
19/// with fallible options for each).
20///
21/// See also [`Subcommand`] and [`Args`].
22///
23/// See the [derive reference](crate::_derive) for attributes and best practices.
24///
25/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features]
26///
27/// # Examples
28///
29/// The following example creates a `Context` struct that would be used
30/// throughout the application representing the normalized values coming from
31/// the CLI.
32///
33#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
34#[cfg_attr(feature = "derive", doc = " ```")]
35/// /// My super CLI
36/// #[derive(clap::Parser)]
37/// #[command(name = "demo")]
38/// struct Context {
39///     /// More verbose output
40///     #[arg(long)]
41///     verbose: bool,
42///     /// An optional name
43///     #[arg(short, long)]
44///     name: Option<String>,
45/// }
46/// ```
47///
48/// The equivalent [`Command`] struct + `From` implementation:
49///
50/// ```rust
51/// # use clap::{Command, Arg, ArgMatches, ArgAction};
52/// Command::new("demo")
53///     .about("My super CLI")
54///     .arg(Arg::new("verbose")
55///         .long("verbose")
56///         .action(ArgAction::SetTrue)
57///         .help("More verbose output"))
58///     .arg(Arg::new("name")
59///         .long("name")
60///         .short('n')
61///         .help("An optional name")
62///         .action(ArgAction::Set));
63///
64/// struct Context {
65///     verbose: bool,
66///     name: Option<String>,
67/// }
68///
69/// impl From<ArgMatches> for Context {
70///     fn from(m: ArgMatches) -> Self {
71///         Context {
72///             verbose: m.get_flag("verbose"),
73///             name: m.get_one::<String>("name").cloned(),
74///         }
75///     }
76/// }
77/// ```
78///
79pub trait Parser: FromArgMatches + CommandFactory + Sized {
80    /// Parse from `std::env::args_os()`, exit on error
81    fn parse() -> Self {
82        let mut matches = <Self as CommandFactory>::command().get_matches();
83        let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
84            .map_err(format_error::<Self>);
85        match res {
86            Ok(s) => s,
87            Err(e) => {
88                // Since this is more of a development-time error, we aren't doing as fancy of a quit
89                // as `get_matches`
90                e.exit()
91            }
92        }
93    }
94
95    /// Parse from `std::env::args_os()`, return Err on error.
96    fn try_parse() -> Result<Self, Error> {
97        let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches());
98        <Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
99    }
100
101    /// Parse from iterator, exit on error
102    fn parse_from<I, T>(itr: I) -> Self
103    where
104        I: IntoIterator<Item = T>,
105        T: Into<OsString> + Clone,
106    {
107        let mut matches = <Self as CommandFactory>::command().get_matches_from(itr);
108        let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
109            .map_err(format_error::<Self>);
110        match res {
111            Ok(s) => s,
112            Err(e) => {
113                // Since this is more of a development-time error, we aren't doing as fancy of a quit
114                // as `get_matches_from`
115                e.exit()
116            }
117        }
118    }
119
120    /// Parse from iterator, return Err on error.
121    fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
122    where
123        I: IntoIterator<Item = T>,
124        T: Into<OsString> + Clone,
125    {
126        let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches_from(itr));
127        <Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
128    }
129
130    /// Update from iterator, exit on error
131    fn update_from<I, T>(&mut self, itr: I)
132    where
133        I: IntoIterator<Item = T>,
134        T: Into<OsString> + Clone,
135    {
136        let mut matches = <Self as CommandFactory>::command_for_update().get_matches_from(itr);
137        let res = <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
138            .map_err(format_error::<Self>);
139        if let Err(e) = res {
140            // Since this is more of a development-time error, we aren't doing as fancy of a quit
141            // as `get_matches_from`
142            e.exit()
143        }
144    }
145
146    /// Update from iterator, return Err on error.
147    fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
148    where
149        I: IntoIterator<Item = T>,
150        T: Into<OsString> + Clone,
151    {
152        let mut matches =
153            ok!(<Self as CommandFactory>::command_for_update().try_get_matches_from(itr));
154        <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
155            .map_err(format_error::<Self>)
156    }
157}
158
159/// Create a [`Command`] relevant for a user-defined container.
160///
161/// Derived as part of [`Parser`].
162pub trait CommandFactory: Sized {
163    /// Build a [`Command`] that can instantiate `Self`.
164    ///
165    /// See [`FromArgMatches::from_arg_matches_mut`] for instantiating `Self`.
166    fn command() -> Command;
167    /// Build a [`Command`] that can update `self`.
168    ///
169    /// See [`FromArgMatches::update_from_arg_matches_mut`] for updating `self`.
170    fn command_for_update() -> Command;
171}
172
173/// Converts an instance of [`ArgMatches`] to a user-defined container.
174///
175/// Derived as part of [`Parser`], [`Args`], and [`Subcommand`].
176pub trait FromArgMatches: Sized {
177    /// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
178    ///
179    /// Motivation: If our application had two CLI options, `--name
180    /// <STRING>` and the flag `--debug`, we may create a struct as follows:
181    ///
182    #[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
183    #[cfg_attr(feature = "derive", doc = " ```no_run")]
184    /// struct Context {
185    ///     name: String,
186    ///     debug: bool
187    /// }
188    /// ```
189    ///
190    /// We then need to convert the `ArgMatches` that `clap` generated into our struct.
191    /// `from_arg_matches` serves as the equivalent of:
192    ///
193    #[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
194    #[cfg_attr(feature = "derive", doc = " ```no_run")]
195    /// # use clap::ArgMatches;
196    /// # struct Context {
197    /// #   name: String,
198    /// #   debug: bool
199    /// # }
200    /// impl From<ArgMatches> for Context {
201    ///    fn from(m: ArgMatches) -> Self {
202    ///        Context {
203    ///            name: m.get_one::<String>("name").unwrap().clone(),
204    ///            debug: m.get_flag("debug"),
205    ///        }
206    ///    }
207    /// }
208    /// ```
209    fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error>;
210
211    /// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
212    ///
213    /// Motivation: If our application had two CLI options, `--name
214    /// <STRING>` and the flag `--debug`, we may create a struct as follows:
215    ///
216    #[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
217    #[cfg_attr(feature = "derive", doc = " ```no_run")]
218    /// struct Context {
219    ///     name: String,
220    ///     debug: bool
221    /// }
222    /// ```
223    ///
224    /// We then need to convert the `ArgMatches` that `clap` generated into our struct.
225    /// `from_arg_matches_mut` serves as the equivalent of:
226    ///
227    #[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
228    #[cfg_attr(feature = "derive", doc = " ```no_run")]
229    /// # use clap::ArgMatches;
230    /// # struct Context {
231    /// #   name: String,
232    /// #   debug: bool
233    /// # }
234    /// impl From<ArgMatches> for Context {
235    ///    fn from(m: ArgMatches) -> Self {
236    ///        Context {
237    ///            name: m.get_one::<String>("name").unwrap().to_string(),
238    ///            debug: m.get_flag("debug"),
239    ///        }
240    ///    }
241    /// }
242    /// ```
243    fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
244        Self::from_arg_matches(matches)
245    }
246
247    /// Assign values from `ArgMatches` to `self`.
248    fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error>;
249
250    /// Assign values from `ArgMatches` to `self`.
251    fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
252        self.update_from_arg_matches(matches)
253    }
254}
255
256/// Parse a set of arguments into a user-defined container.
257///
258/// Implementing this trait lets a parent container delegate argument parsing behavior to `Self`.
259/// with:
260/// - `#[command(flatten)] args: ChildArgs`: Attribute can only be used with struct fields that impl
261///   `Args`.
262/// - `Variant(ChildArgs)`: No attribute is used with enum variants that impl `Args`.
263///
264/// See the [derive reference](crate::_derive) for attributes and best practices.
265///
266/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features]
267///
268/// # Example
269///
270#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
271#[cfg_attr(feature = "derive", doc = " ```")]
272/// #[derive(clap::Parser)]
273/// struct Args {
274///     #[command(flatten)]
275///     logging: LogArgs,
276/// }
277///
278/// #[derive(clap::Args)]
279/// struct LogArgs {
280///     #[arg(long, short = 'v', action = clap::ArgAction::Count)]
281///     verbose: u8,
282/// }
283/// ```
284pub trait Args: FromArgMatches + Sized {
285    /// Report the [`ArgGroup::id`][crate::ArgGroup::id] for this set of arguments
286    fn group_id() -> Option<crate::Id> {
287        None
288    }
289    /// Append to [`Command`] so it can instantiate `Self`.
290    ///
291    /// See also [`CommandFactory`].
292    fn augment_args(cmd: Command) -> Command;
293    /// Append to [`Command`] so it can update `self`.
294    ///
295    /// This is used to implement `#[command(flatten)]`
296    ///
297    /// See also [`CommandFactory`].
298    fn augment_args_for_update(cmd: Command) -> Command;
299}
300
301/// Parse a sub-command into a user-defined enum.
302///
303/// Implementing this trait lets a parent container delegate subcommand behavior to `Self`.
304/// with:
305/// - `#[command(subcommand)] field: SubCmd`: Attribute can be used with either struct fields or enum
306///   variants that impl `Subcommand`.
307/// - `#[command(flatten)] Variant(SubCmd)`: Attribute can only be used with enum variants that impl
308///   `Subcommand`.
309///
310/// See the [derive reference](crate::_derive) for attributes and best practices.
311///
312/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features]
313///
314/// # Example
315///
316#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
317#[cfg_attr(feature = "derive", doc = " ```")]
318/// #[derive(clap::Parser)]
319/// struct Args {
320///     #[command(subcommand)]
321///     action: Action,
322/// }
323///
324/// #[derive(clap::Subcommand)]
325/// enum Action {
326///     Add,
327///     Remove,
328/// }
329/// ```
330pub trait Subcommand: FromArgMatches + Sized {
331    /// Append to [`Command`] so it can instantiate `Self`.
332    ///
333    /// See also [`CommandFactory`].
334    fn augment_subcommands(cmd: Command) -> Command;
335    /// Append to [`Command`] so it can update `self`.
336    ///
337    /// This is used to implement `#[command(flatten)]`
338    ///
339    /// See also [`CommandFactory`].
340    fn augment_subcommands_for_update(cmd: Command) -> Command;
341    /// Test whether `Self` can parse a specific subcommand
342    fn has_subcommand(name: &str) -> bool;
343}
344
345/// Parse arguments into enums.
346///
347/// When deriving [`Parser`], a field whose type implements `ValueEnum` can have the attribute
348/// `#[arg(value_enum)]` which will
349/// - Call [`EnumValueParser`][crate::builder::EnumValueParser]
350/// - Allowing using the `#[arg(default_value_t)]` attribute without implementing `Display`.
351///
352/// See the [derive reference](crate::_derive) for attributes and best practices.
353///
354/// **NOTE:** Deriving requires the [`derive` feature flag][crate::_features]
355///
356/// # Example
357///
358#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
359#[cfg_attr(feature = "derive", doc = " ```")]
360/// #[derive(clap::Parser)]
361/// struct Args {
362///     #[arg(value_enum)]
363///     level: Level,
364/// }
365///
366/// #[derive(clap::ValueEnum, Clone)]
367/// enum Level {
368///     Debug,
369///     Info,
370///     Warning,
371///     Error,
372/// }
373/// ```
374pub trait ValueEnum: Sized + Clone {
375    /// All possible argument values, in display order.
376    fn value_variants<'a>() -> &'a [Self];
377
378    /// Parse an argument into `Self`.
379    fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> {
380        Self::value_variants()
381            .iter()
382            .find(|v| {
383                v.to_possible_value()
384                    .expect("ValueEnum::value_variants contains only values with a corresponding ValueEnum::to_possible_value")
385                    .matches(input, ignore_case)
386            })
387            .cloned()
388            .ok_or_else(|| format!("invalid variant: {input}"))
389    }
390
391    /// The canonical argument value.
392    ///
393    /// The value is `None` for skipped variants.
394    fn to_possible_value(&self) -> Option<PossibleValue>;
395}
396
397impl<T: Parser> Parser for Box<T> {
398    fn parse() -> Self {
399        Box::new(<T as Parser>::parse())
400    }
401
402    fn try_parse() -> Result<Self, Error> {
403        <T as Parser>::try_parse().map(Box::new)
404    }
405
406    fn parse_from<I, It>(itr: I) -> Self
407    where
408        I: IntoIterator<Item = It>,
409        It: Into<OsString> + Clone,
410    {
411        Box::new(<T as Parser>::parse_from(itr))
412    }
413
414    fn try_parse_from<I, It>(itr: I) -> Result<Self, Error>
415    where
416        I: IntoIterator<Item = It>,
417        It: Into<OsString> + Clone,
418    {
419        <T as Parser>::try_parse_from(itr).map(Box::new)
420    }
421}
422
423impl<T: CommandFactory> CommandFactory for Box<T> {
424    fn command<'help>() -> Command {
425        <T as CommandFactory>::command()
426    }
427    fn command_for_update<'help>() -> Command {
428        <T as CommandFactory>::command_for_update()
429    }
430}
431
432impl<T: FromArgMatches> FromArgMatches for Box<T> {
433    fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
434        <T as FromArgMatches>::from_arg_matches(matches).map(Box::new)
435    }
436    fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
437        <T as FromArgMatches>::from_arg_matches_mut(matches).map(Box::new)
438    }
439    fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
440        <T as FromArgMatches>::update_from_arg_matches(self, matches)
441    }
442    fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
443        <T as FromArgMatches>::update_from_arg_matches_mut(self, matches)
444    }
445}
446
447impl<T: Args> Args for Box<T> {
448    fn augment_args(cmd: Command) -> Command {
449        <T as Args>::augment_args(cmd)
450    }
451    fn augment_args_for_update(cmd: Command) -> Command {
452        <T as Args>::augment_args_for_update(cmd)
453    }
454}
455
456impl<T: Subcommand> Subcommand for Box<T> {
457    fn augment_subcommands(cmd: Command) -> Command {
458        <T as Subcommand>::augment_subcommands(cmd)
459    }
460    fn augment_subcommands_for_update(cmd: Command) -> Command {
461        <T as Subcommand>::augment_subcommands_for_update(cmd)
462    }
463    fn has_subcommand(name: &str) -> bool {
464        <T as Subcommand>::has_subcommand(name)
465    }
466}
467
468fn format_error<I: CommandFactory>(err: crate::Error) -> crate::Error {
469    let mut cmd = I::command();
470    err.format(&mut cmd)
471}
472