clap_builder/
derive.rs

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/// **NOTE:** Deriving requires the `derive` feature flag
24pub trait Parser: FromArgMatches + CommandFactory + Sized {
25    /// Parse from `std::env::args_os()`, [exit][Error::exit] on error.
26    fn parse() -> Self {
27        let mut matches = <Self as CommandFactory>::command().get_matches();
28        let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
29            .map_err(format_error::<Self>);
30        match res {
31            Ok(s) => s,
32            Err(e) => {
33                // Since this is more of a development-time error, we aren't doing as fancy of a quit
34                // as `get_matches`
35                e.exit()
36            }
37        }
38    }
39
40    /// Parse from `std::env::args_os()`, return Err on error.
41    fn try_parse() -> Result<Self, Error> {
42        let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches());
43        <Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
44    }
45
46    /// Parse from iterator, [exit][Error::exit] on error.
47    fn parse_from<I, T>(itr: I) -> Self
48    where
49        I: IntoIterator<Item = T>,
50        T: Into<OsString> + Clone,
51    {
52        let mut matches = <Self as CommandFactory>::command().get_matches_from(itr);
53        let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
54            .map_err(format_error::<Self>);
55        match res {
56            Ok(s) => s,
57            Err(e) => {
58                // Since this is more of a development-time error, we aren't doing as fancy of a quit
59                // as `get_matches_from`
60                e.exit()
61            }
62        }
63    }
64
65    /// Parse from iterator, return Err on error.
66    fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
67    where
68        I: IntoIterator<Item = T>,
69        T: Into<OsString> + Clone,
70    {
71        let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches_from(itr));
72        <Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
73    }
74
75    /// Update from iterator, [exit][Error::exit] on error.
76    fn update_from<I, T>(&mut self, itr: I)
77    where
78        I: IntoIterator<Item = T>,
79        T: Into<OsString> + Clone,
80    {
81        let mut matches = <Self as CommandFactory>::command_for_update().get_matches_from(itr);
82        let res = <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
83            .map_err(format_error::<Self>);
84        if let Err(e) = res {
85            // Since this is more of a development-time error, we aren't doing as fancy of a quit
86            // as `get_matches_from`
87            e.exit()
88        }
89    }
90
91    /// Update from iterator, return Err on error.
92    fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
93    where
94        I: IntoIterator<Item = T>,
95        T: Into<OsString> + Clone,
96    {
97        let mut matches =
98            ok!(<Self as CommandFactory>::command_for_update().try_get_matches_from(itr));
99        <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
100            .map_err(format_error::<Self>)
101    }
102}
103
104/// Create a [`Command`] relevant for a user-defined container.
105///
106/// Derived as part of [`Parser`].
107pub trait CommandFactory: Sized {
108    /// Build a [`Command`] that can instantiate `Self`.
109    ///
110    /// See [`FromArgMatches::from_arg_matches_mut`] for instantiating `Self`.
111    fn command() -> Command;
112    /// Build a [`Command`] that can update `self`.
113    ///
114    /// See [`FromArgMatches::update_from_arg_matches_mut`] for updating `self`.
115    fn command_for_update() -> Command;
116}
117
118/// Converts an instance of [`ArgMatches`] to a user-defined container.
119///
120/// Derived as part of [`Parser`], [`Args`], and [`Subcommand`].
121pub trait FromArgMatches: Sized {
122    /// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
123    ///
124    /// Motivation: If our application had two CLI options, `--name
125    /// <STRING>` and the flag `--debug`, we may create a struct as follows:
126    ///
127    /// ```rust
128    /// # #[cfg(feature = "derive")] {
129    /// struct Context {
130    ///     name: String,
131    ///     debug: bool
132    /// }
133    /// # }
134    /// ```
135    ///
136    /// We then need to convert the `ArgMatches` that `clap` generated into our struct.
137    /// `from_arg_matches` serves as the equivalent of:
138    ///
139    /// ```rust
140    /// # #[cfg(feature = "derive")] {
141    /// # use clap::ArgMatches;
142    /// # struct Context {
143    /// #   name: String,
144    /// #   debug: bool
145    /// # }
146    /// impl From<ArgMatches> for Context {
147    ///    fn from(m: ArgMatches) -> Self {
148    ///        Context {
149    ///            name: m.get_one::<String>("name").unwrap().clone(),
150    ///            debug: m.get_flag("debug"),
151    ///        }
152    ///    }
153    /// }
154    /// # }
155    /// ```
156    fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error>;
157
158    /// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
159    ///
160    /// Motivation: If our application had two CLI options, `--name
161    /// <STRING>` and the flag `--debug`, we may create a struct as follows:
162    ///
163    /// ```rust
164    /// # #[cfg(feature = "derive")] {
165    /// struct Context {
166    ///     name: String,
167    ///     debug: bool
168    /// }
169    /// # }
170    /// ```
171    ///
172    /// We then need to convert the `ArgMatches` that `clap` generated into our struct.
173    /// `from_arg_matches_mut` serves as the equivalent of:
174    ///
175    /// ```rust
176    /// # #[cfg(feature = "derive")] {
177    /// # use clap::ArgMatches;
178    /// # struct Context {
179    /// #   name: String,
180    /// #   debug: bool
181    /// # }
182    /// impl From<ArgMatches> for Context {
183    ///    fn from(m: ArgMatches) -> Self {
184    ///        Context {
185    ///            name: m.get_one::<String>("name").unwrap().to_string(),
186    ///            debug: m.get_flag("debug"),
187    ///        }
188    ///    }
189    /// }
190    /// # }
191    /// ```
192    fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
193        Self::from_arg_matches(matches)
194    }
195
196    /// Assign values from `ArgMatches` to `self`.
197    fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error>;
198
199    /// Assign values from `ArgMatches` to `self`.
200    fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
201        self.update_from_arg_matches(matches)
202    }
203}
204
205/// Parse a set of arguments into a user-defined container.
206///
207/// Implementing this trait lets a parent container delegate argument parsing behavior to `Self`.
208/// with:
209/// - `#[command(flatten)] args: ChildArgs`: Attribute can only be used with struct fields that impl
210///   `Args`.
211/// - `Variant(ChildArgs)`: No attribute is used with enum variants that impl `Args`.
212///
213/// **NOTE:** Deriving requires the `derive` feature flag
214pub trait Args: FromArgMatches + Sized {
215    /// Report the [`ArgGroup::id`][crate::ArgGroup::id] for this set of arguments
216    fn group_id() -> Option<crate::Id> {
217        None
218    }
219    /// Append to [`Command`] so it can instantiate `Self`.
220    ///
221    /// See also [`CommandFactory`].
222    fn augment_args(cmd: Command) -> Command;
223    /// Append to [`Command`] so it can update `self`.
224    ///
225    /// This is used to implement `#[command(flatten)]`
226    ///
227    /// See also [`CommandFactory`].
228    fn augment_args_for_update(cmd: Command) -> Command;
229}
230
231/// Parse a sub-command into a user-defined enum.
232///
233/// Implementing this trait lets a parent container delegate subcommand behavior to `Self`.
234/// with:
235/// - `#[command(subcommand)] field: SubCmd`: Attribute can be used with either struct fields or enum
236///   variants that impl `Subcommand`.
237/// - `#[command(flatten)] Variant(SubCmd)`: Attribute can only be used with enum variants that impl
238///   `Subcommand`.
239///
240/// **NOTE:** Deriving requires the `derive` feature flag
241pub trait Subcommand: FromArgMatches + Sized {
242    /// Append to [`Command`] so it can instantiate `Self`.
243    ///
244    /// See also [`CommandFactory`].
245    fn augment_subcommands(cmd: Command) -> Command;
246    /// Append to [`Command`] so it can update `self`.
247    ///
248    /// This is used to implement `#[command(flatten)]`
249    ///
250    /// See also [`CommandFactory`].
251    fn augment_subcommands_for_update(cmd: Command) -> Command;
252    /// Test whether `Self` can parse a specific subcommand
253    fn has_subcommand(name: &str) -> bool;
254}
255
256/// Parse arguments into enums.
257///
258/// When deriving [`Parser`], a field whose type implements `ValueEnum` can have the attribute
259/// `#[arg(value_enum)]` which will
260/// - Call [`EnumValueParser`][crate::builder::EnumValueParser]
261/// - Allowing using the `#[arg(default_value_t)]` attribute without implementing `Display`.
262///
263/// **NOTE:** Deriving requires the `derive` feature flag
264pub trait ValueEnum: Sized + Clone {
265    /// All possible argument values, in display order.
266    fn value_variants<'a>() -> &'a [Self];
267
268    /// Parse an argument into `Self`.
269    fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> {
270        Self::value_variants()
271            .iter()
272            .find(|v| {
273                v.to_possible_value()
274                    .expect("ValueEnum::value_variants contains only values with a corresponding ValueEnum::to_possible_value")
275                    .matches(input, ignore_case)
276            })
277            .cloned()
278            .ok_or_else(|| format!("invalid variant: {input}"))
279    }
280
281    /// The canonical argument value.
282    ///
283    /// The value is `None` for skipped variants.
284    fn to_possible_value(&self) -> Option<PossibleValue>;
285}
286
287impl<T: Parser> Parser for Box<T> {
288    fn parse() -> Self {
289        Box::new(<T as Parser>::parse())
290    }
291
292    fn try_parse() -> Result<Self, Error> {
293        <T as Parser>::try_parse().map(Box::new)
294    }
295
296    fn parse_from<I, It>(itr: I) -> Self
297    where
298        I: IntoIterator<Item = It>,
299        It: Into<OsString> + Clone,
300    {
301        Box::new(<T as Parser>::parse_from(itr))
302    }
303
304    fn try_parse_from<I, It>(itr: I) -> Result<Self, Error>
305    where
306        I: IntoIterator<Item = It>,
307        It: Into<OsString> + Clone,
308    {
309        <T as Parser>::try_parse_from(itr).map(Box::new)
310    }
311}
312
313impl<T: CommandFactory> CommandFactory for Box<T> {
314    fn command() -> Command {
315        <T as CommandFactory>::command()
316    }
317    fn command_for_update() -> Command {
318        <T as CommandFactory>::command_for_update()
319    }
320}
321
322impl<T: FromArgMatches> FromArgMatches for Box<T> {
323    fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
324        <T as FromArgMatches>::from_arg_matches(matches).map(Box::new)
325    }
326    fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
327        <T as FromArgMatches>::from_arg_matches_mut(matches).map(Box::new)
328    }
329    fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
330        <T as FromArgMatches>::update_from_arg_matches(self, matches)
331    }
332    fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
333        <T as FromArgMatches>::update_from_arg_matches_mut(self, matches)
334    }
335}
336
337impl<T: Args> Args for Box<T> {
338    fn augment_args(cmd: Command) -> Command {
339        <T as Args>::augment_args(cmd)
340    }
341    fn augment_args_for_update(cmd: Command) -> Command {
342        <T as Args>::augment_args_for_update(cmd)
343    }
344}
345
346impl<T: Subcommand> Subcommand for Box<T> {
347    fn augment_subcommands(cmd: Command) -> Command {
348        <T as Subcommand>::augment_subcommands(cmd)
349    }
350    fn augment_subcommands_for_update(cmd: Command) -> Command {
351        <T as Subcommand>::augment_subcommands_for_update(cmd)
352    }
353    fn has_subcommand(name: &str) -> bool {
354        <T as Subcommand>::has_subcommand(name)
355    }
356}
357
358fn format_error<I: CommandFactory>(err: Error) -> Error {
359    let mut cmd = I::command();
360    err.format(&mut cmd)
361}