1 | //! This module contains traits that are usable with the `#[derive(...)]` |
2 | //! macros in `clap_derive`. |
3 | |
4 | use crate::builder::PossibleValue; |
5 | use crate::{ArgMatches, Command, Error}; |
6 | |
7 | use 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> |
28 | pub 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`]. |
115 | pub 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`]. |
129 | pub 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> |
226 | pub 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> |
261 | pub 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> |
292 | pub 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 | |
315 | impl<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 | |
341 | impl<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 | |
350 | impl<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(op: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(op: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 | |
365 | impl<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 | |
374 | impl<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 | |
386 | fn format_error<I: CommandFactory>(err: Error) -> Error { |
387 | let mut cmd: Command = I::command(); |
388 | err.format(&mut cmd) |
389 | } |
390 | |