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