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 | /// **NOTE:** Deriving requires the `derive` feature flag |
24 | pub trait Parser: FromArgMatches + CommandFactory + Sized { |
25 | /// Parse from `std::env::args_os()`, 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 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 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`]. |
107 | pub 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`]. |
121 | pub 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 |
214 | pub 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 |
241 | pub 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 |
264 | pub 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 | |
287 | impl<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 | |
313 | impl<T: CommandFactory> CommandFactory for Box<T> { |
314 | fn command<'help>() -> Command { |
315 | <T as CommandFactory>::command() |
316 | } |
317 | fn command_for_update<'help>() -> Command { |
318 | <T as CommandFactory>::command_for_update() |
319 | } |
320 | } |
321 | |
322 | impl<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(op: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(op: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 | |
337 | impl<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 | |
346 | impl<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 | |
358 | fn format_error<I: CommandFactory>(err: crate::Error) -> crate::Error { |
359 | let mut cmd: Command = I::command(); |
360 | err.format(&mut cmd) |
361 | } |
362 | |