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