1 | use std::convert::TryInto; |
2 | use std::ops::RangeBounds; |
3 | |
4 | use crate::builder::Str; |
5 | use crate::builder::StyledStr; |
6 | use crate::parser::ValueSource; |
7 | use crate::util::AnyValue; |
8 | use crate::util::AnyValueId; |
9 | |
10 | /// Parse/validate argument values |
11 | /// |
12 | /// Specified with [`Arg::value_parser`][crate::Arg::value_parser]. |
13 | /// |
14 | /// `ValueParser` defines how to convert a raw argument value into a validated and typed value for |
15 | /// use within an application. |
16 | /// |
17 | /// See |
18 | /// - [`value_parser!`][crate::value_parser] for automatically selecting an implementation for a given type |
19 | /// - [`ValueParser::new`] for additional [`TypedValueParser`] that can be used |
20 | /// |
21 | /// # Example |
22 | /// |
23 | /// ```rust |
24 | /// # use clap_builder as clap; |
25 | /// let mut cmd = clap::Command::new("raw" ) |
26 | /// .arg( |
27 | /// clap::Arg::new("color" ) |
28 | /// .long("color" ) |
29 | /// .value_parser(["always" , "auto" , "never" ]) |
30 | /// .default_value("auto" ) |
31 | /// ) |
32 | /// .arg( |
33 | /// clap::Arg::new("hostname" ) |
34 | /// .long("hostname" ) |
35 | /// .value_parser(clap::builder::NonEmptyStringValueParser::new()) |
36 | /// .action(clap::ArgAction::Set) |
37 | /// .required(true) |
38 | /// ) |
39 | /// .arg( |
40 | /// clap::Arg::new("port" ) |
41 | /// .long("port" ) |
42 | /// .value_parser(clap::value_parser!(u16).range(3000..)) |
43 | /// .action(clap::ArgAction::Set) |
44 | /// .required(true) |
45 | /// ); |
46 | /// |
47 | /// let m = cmd.try_get_matches_from_mut( |
48 | /// ["cmd" , "--hostname" , "rust-lang.org" , "--port" , "3001" ] |
49 | /// ).unwrap(); |
50 | /// |
51 | /// let color: &String = m.get_one("color" ) |
52 | /// .expect("default" ); |
53 | /// assert_eq!(color, "auto" ); |
54 | /// |
55 | /// let hostname: &String = m.get_one("hostname" ) |
56 | /// .expect("required" ); |
57 | /// assert_eq!(hostname, "rust-lang.org" ); |
58 | /// |
59 | /// let port: u16 = *m.get_one("port" ) |
60 | /// .expect("required" ); |
61 | /// assert_eq!(port, 3001); |
62 | /// ``` |
63 | pub struct ValueParser(ValueParserInner); |
64 | |
65 | enum ValueParserInner { |
66 | // Common enough to optimize and for possible values |
67 | Bool, |
68 | // Common enough to optimize |
69 | String, |
70 | // Common enough to optimize |
71 | OsString, |
72 | // Common enough to optimize |
73 | PathBuf, |
74 | Other(Box<dyn AnyValueParser>), |
75 | } |
76 | |
77 | impl ValueParser { |
78 | /// Custom parser for argument values |
79 | /// |
80 | /// Pre-existing [`TypedValueParser`] implementations include: |
81 | /// - `Fn(&str) -> Result<T, E>` |
82 | /// - [`EnumValueParser`] and [`PossibleValuesParser`] for static enumerated values |
83 | /// - [`BoolishValueParser`] and [`FalseyValueParser`] for alternative `bool` implementations |
84 | /// - [`RangedI64ValueParser`] and [`RangedU64ValueParser`] |
85 | /// - [`NonEmptyStringValueParser`] |
86 | /// |
87 | /// # Example |
88 | /// |
89 | /// ```rust |
90 | /// # use clap_builder as clap; |
91 | /// type EnvVar = (String, Option<String>); |
92 | /// fn parse_env_var(env: &str) -> Result<EnvVar, std::io::Error> { |
93 | /// if let Some((var, value)) = env.split_once('=' ) { |
94 | /// Ok((var.to_owned(), Some(value.to_owned()))) |
95 | /// } else { |
96 | /// Ok((env.to_owned(), None)) |
97 | /// } |
98 | /// } |
99 | /// |
100 | /// let mut cmd = clap::Command::new("raw" ) |
101 | /// .arg( |
102 | /// clap::Arg::new("env" ) |
103 | /// .value_parser(clap::builder::ValueParser::new(parse_env_var)) |
104 | /// .required(true) |
105 | /// ); |
106 | /// |
107 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "key=value" ]).unwrap(); |
108 | /// let port: &EnvVar = m.get_one("env" ) |
109 | /// .expect("required" ); |
110 | /// assert_eq!(*port, ("key" .into(), Some("value" .into()))); |
111 | /// ``` |
112 | pub fn new<P>(other: P) -> Self |
113 | where |
114 | P: TypedValueParser, |
115 | { |
116 | Self(ValueParserInner::Other(Box::new(other))) |
117 | } |
118 | |
119 | /// [`bool`] parser for argument values |
120 | /// |
121 | /// See also: |
122 | /// - [`BoolishValueParser`] for different human readable bool representations |
123 | /// - [`FalseyValueParser`] for assuming non-false is true |
124 | /// |
125 | /// # Example |
126 | /// |
127 | /// ```rust |
128 | /// # use clap_builder as clap; |
129 | /// let mut cmd = clap::Command::new("raw" ) |
130 | /// .arg( |
131 | /// clap::Arg::new("download" ) |
132 | /// .value_parser(clap::value_parser!(bool)) |
133 | /// .required(true) |
134 | /// ); |
135 | /// |
136 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "true" ]).unwrap(); |
137 | /// let port: bool = *m.get_one("download" ) |
138 | /// .expect("required" ); |
139 | /// assert_eq!(port, true); |
140 | /// |
141 | /// assert!(cmd.try_get_matches_from_mut(["cmd" , "forever" ]).is_err()); |
142 | /// ``` |
143 | pub const fn bool() -> Self { |
144 | Self(ValueParserInner::Bool) |
145 | } |
146 | |
147 | /// [`String`] parser for argument values |
148 | /// |
149 | /// See also: |
150 | /// - [`NonEmptyStringValueParser`] |
151 | /// |
152 | /// # Example |
153 | /// |
154 | /// ```rust |
155 | /// # use clap_builder as clap; |
156 | /// let mut cmd = clap::Command::new("raw" ) |
157 | /// .arg( |
158 | /// clap::Arg::new("port" ) |
159 | /// .value_parser(clap::value_parser!(String)) |
160 | /// .required(true) |
161 | /// ); |
162 | /// |
163 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "80" ]).unwrap(); |
164 | /// let port: &String = m.get_one("port" ) |
165 | /// .expect("required" ); |
166 | /// assert_eq!(port, "80" ); |
167 | /// ``` |
168 | pub const fn string() -> Self { |
169 | Self(ValueParserInner::String) |
170 | } |
171 | |
172 | /// [`OsString`][std::ffi::OsString] parser for argument values |
173 | /// |
174 | /// # Example |
175 | /// |
176 | /// ```rust |
177 | /// # #[cfg (unix)] { |
178 | /// # use clap_builder as clap; |
179 | /// # use clap::{Command, Arg, builder::ValueParser}; |
180 | /// use std::ffi::OsString; |
181 | /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; |
182 | /// let r = Command::new("myprog" ) |
183 | /// .arg( |
184 | /// Arg::new("arg" ) |
185 | /// .required(true) |
186 | /// .value_parser(ValueParser::os_string()) |
187 | /// ) |
188 | /// .try_get_matches_from(vec![ |
189 | /// OsString::from("myprog" ), |
190 | /// OsString::from_vec(vec![0xe9]) |
191 | /// ]); |
192 | /// |
193 | /// assert!(r.is_ok()); |
194 | /// let m = r.unwrap(); |
195 | /// let arg: &OsString = m.get_one("arg" ) |
196 | /// .expect("required" ); |
197 | /// assert_eq!(arg.as_bytes(), &[0xe9]); |
198 | /// # } |
199 | /// ``` |
200 | pub const fn os_string() -> Self { |
201 | Self(ValueParserInner::OsString) |
202 | } |
203 | |
204 | /// [`PathBuf`][std::path::PathBuf] parser for argument values |
205 | /// |
206 | /// # Example |
207 | /// |
208 | /// ```rust |
209 | /// # use clap_builder as clap; |
210 | /// # use std::path::PathBuf; |
211 | /// # use std::path::Path; |
212 | /// let mut cmd = clap::Command::new("raw" ) |
213 | /// .arg( |
214 | /// clap::Arg::new("output" ) |
215 | /// .value_parser(clap::value_parser!(PathBuf)) |
216 | /// .required(true) |
217 | /// ); |
218 | /// |
219 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "hello.txt" ]).unwrap(); |
220 | /// let port: &PathBuf = m.get_one("output" ) |
221 | /// .expect("required" ); |
222 | /// assert_eq!(port, Path::new("hello.txt" )); |
223 | /// |
224 | /// assert!(cmd.try_get_matches_from_mut(["cmd" , "" ]).is_err()); |
225 | /// ``` |
226 | pub const fn path_buf() -> Self { |
227 | Self(ValueParserInner::PathBuf) |
228 | } |
229 | } |
230 | |
231 | impl ValueParser { |
232 | /// Parse into a `AnyValue` |
233 | /// |
234 | /// When `arg` is `None`, an external subcommand value is being parsed. |
235 | pub(crate) fn parse_ref( |
236 | &self, |
237 | cmd: &crate::Command, |
238 | arg: Option<&crate::Arg>, |
239 | value: &std::ffi::OsStr, |
240 | source: ValueSource, |
241 | ) -> Result<AnyValue, crate::Error> { |
242 | self.any_value_parser().parse_ref_(cmd, arg, value, source) |
243 | } |
244 | |
245 | /// Describes the content of `AnyValue` |
246 | pub fn type_id(&self) -> AnyValueId { |
247 | self.any_value_parser().type_id() |
248 | } |
249 | |
250 | /// Reflect on enumerated value properties |
251 | /// |
252 | /// Error checking should not be done with this; it is mostly targeted at user-facing |
253 | /// applications like errors and completion. |
254 | pub fn possible_values( |
255 | &self, |
256 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
257 | self.any_value_parser().possible_values() |
258 | } |
259 | |
260 | fn any_value_parser(&self) -> &dyn AnyValueParser { |
261 | match &self.0 { |
262 | ValueParserInner::Bool => &BoolValueParser {}, |
263 | ValueParserInner::String => &StringValueParser {}, |
264 | ValueParserInner::OsString => &OsStringValueParser {}, |
265 | ValueParserInner::PathBuf => &PathBufValueParser {}, |
266 | ValueParserInner::Other(o) => o.as_ref(), |
267 | } |
268 | } |
269 | } |
270 | |
271 | /// Convert a [`TypedValueParser`] to [`ValueParser`] |
272 | /// |
273 | /// # Example |
274 | /// |
275 | /// ```rust |
276 | /// # use clap_builder as clap; |
277 | /// let mut cmd = clap::Command::new("raw" ) |
278 | /// .arg( |
279 | /// clap::Arg::new("hostname" ) |
280 | /// .long("hostname" ) |
281 | /// .value_parser(clap::builder::NonEmptyStringValueParser::new()) |
282 | /// .action(clap::ArgAction::Set) |
283 | /// .required(true) |
284 | /// ); |
285 | /// |
286 | /// let m = cmd.try_get_matches_from_mut( |
287 | /// ["cmd" , "--hostname" , "rust-lang.org" ] |
288 | /// ).unwrap(); |
289 | /// |
290 | /// let hostname: &String = m.get_one("hostname" ) |
291 | /// .expect("required" ); |
292 | /// assert_eq!(hostname, "rust-lang.org" ); |
293 | /// ``` |
294 | impl<P> From<P> for ValueParser |
295 | where |
296 | P: TypedValueParser + Send + Sync + 'static, |
297 | { |
298 | fn from(p: P) -> Self { |
299 | Self::new(p) |
300 | } |
301 | } |
302 | |
303 | impl From<_AnonymousValueParser> for ValueParser { |
304 | fn from(p: _AnonymousValueParser) -> Self { |
305 | p.0 |
306 | } |
307 | } |
308 | |
309 | /// Create an `i64` [`ValueParser`] from a `N..M` range |
310 | /// |
311 | /// See [`RangedI64ValueParser`] for more control over the output type. |
312 | /// |
313 | /// See also [`RangedU64ValueParser`] |
314 | /// |
315 | /// # Examples |
316 | /// |
317 | /// ```rust |
318 | /// # use clap_builder as clap; |
319 | /// let mut cmd = clap::Command::new("raw" ) |
320 | /// .arg( |
321 | /// clap::Arg::new("port" ) |
322 | /// .long("port" ) |
323 | /// .value_parser(3000..4000) |
324 | /// .action(clap::ArgAction::Set) |
325 | /// .required(true) |
326 | /// ); |
327 | /// |
328 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "3001" ]).unwrap(); |
329 | /// let port: i64 = *m.get_one("port" ) |
330 | /// .expect("required" ); |
331 | /// assert_eq!(port, 3001); |
332 | /// ``` |
333 | impl From<std::ops::Range<i64>> for ValueParser { |
334 | fn from(value: std::ops::Range<i64>) -> Self { |
335 | let inner = RangedI64ValueParser::<i64>::new().range(value.start..value.end); |
336 | Self::from(inner) |
337 | } |
338 | } |
339 | |
340 | /// Create an `i64` [`ValueParser`] from a `N..=M` range |
341 | /// |
342 | /// See [`RangedI64ValueParser`] for more control over the output type. |
343 | /// |
344 | /// See also [`RangedU64ValueParser`] |
345 | /// |
346 | /// # Examples |
347 | /// |
348 | /// ```rust |
349 | /// # use clap_builder as clap; |
350 | /// let mut cmd = clap::Command::new("raw" ) |
351 | /// .arg( |
352 | /// clap::Arg::new("port" ) |
353 | /// .long("port" ) |
354 | /// .value_parser(3000..=4000) |
355 | /// .action(clap::ArgAction::Set) |
356 | /// .required(true) |
357 | /// ); |
358 | /// |
359 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "3001" ]).unwrap(); |
360 | /// let port: i64 = *m.get_one("port" ) |
361 | /// .expect("required" ); |
362 | /// assert_eq!(port, 3001); |
363 | /// ``` |
364 | impl From<std::ops::RangeInclusive<i64>> for ValueParser { |
365 | fn from(value: std::ops::RangeInclusive<i64>) -> Self { |
366 | let inner = RangedI64ValueParser::<i64>::new().range(value.start()..=value.end()); |
367 | Self::from(inner) |
368 | } |
369 | } |
370 | |
371 | /// Create an `i64` [`ValueParser`] from a `N..` range |
372 | /// |
373 | /// See [`RangedI64ValueParser`] for more control over the output type. |
374 | /// |
375 | /// See also [`RangedU64ValueParser`] |
376 | /// |
377 | /// # Examples |
378 | /// |
379 | /// ```rust |
380 | /// # use clap_builder as clap; |
381 | /// let mut cmd = clap::Command::new("raw" ) |
382 | /// .arg( |
383 | /// clap::Arg::new("port" ) |
384 | /// .long("port" ) |
385 | /// .value_parser(3000..) |
386 | /// .action(clap::ArgAction::Set) |
387 | /// .required(true) |
388 | /// ); |
389 | /// |
390 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "3001" ]).unwrap(); |
391 | /// let port: i64 = *m.get_one("port" ) |
392 | /// .expect("required" ); |
393 | /// assert_eq!(port, 3001); |
394 | /// ``` |
395 | impl From<std::ops::RangeFrom<i64>> for ValueParser { |
396 | fn from(value: std::ops::RangeFrom<i64>) -> Self { |
397 | let inner = RangedI64ValueParser::<i64>::new().range(value.start..); |
398 | Self::from(inner) |
399 | } |
400 | } |
401 | |
402 | /// Create an `i64` [`ValueParser`] from a `..M` range |
403 | /// |
404 | /// See [`RangedI64ValueParser`] for more control over the output type. |
405 | /// |
406 | /// See also [`RangedU64ValueParser`] |
407 | /// |
408 | /// # Examples |
409 | /// |
410 | /// ```rust |
411 | /// # use clap_builder as clap; |
412 | /// let mut cmd = clap::Command::new("raw" ) |
413 | /// .arg( |
414 | /// clap::Arg::new("port" ) |
415 | /// .long("port" ) |
416 | /// .value_parser(..3000) |
417 | /// .action(clap::ArgAction::Set) |
418 | /// .required(true) |
419 | /// ); |
420 | /// |
421 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "80" ]).unwrap(); |
422 | /// let port: i64 = *m.get_one("port" ) |
423 | /// .expect("required" ); |
424 | /// assert_eq!(port, 80); |
425 | /// ``` |
426 | impl From<std::ops::RangeTo<i64>> for ValueParser { |
427 | fn from(value: std::ops::RangeTo<i64>) -> Self { |
428 | let inner = RangedI64ValueParser::<i64>::new().range(..value.end); |
429 | Self::from(inner) |
430 | } |
431 | } |
432 | |
433 | /// Create an `i64` [`ValueParser`] from a `..=M` range |
434 | /// |
435 | /// See [`RangedI64ValueParser`] for more control over the output type. |
436 | /// |
437 | /// See also [`RangedU64ValueParser`] |
438 | /// |
439 | /// # Examples |
440 | /// |
441 | /// ```rust |
442 | /// # use clap_builder as clap; |
443 | /// let mut cmd = clap::Command::new("raw" ) |
444 | /// .arg( |
445 | /// clap::Arg::new("port" ) |
446 | /// .long("port" ) |
447 | /// .value_parser(..=3000) |
448 | /// .action(clap::ArgAction::Set) |
449 | /// .required(true) |
450 | /// ); |
451 | /// |
452 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "80" ]).unwrap(); |
453 | /// let port: i64 = *m.get_one("port" ) |
454 | /// .expect("required" ); |
455 | /// assert_eq!(port, 80); |
456 | /// ``` |
457 | impl From<std::ops::RangeToInclusive<i64>> for ValueParser { |
458 | fn from(value: std::ops::RangeToInclusive<i64>) -> Self { |
459 | let inner = RangedI64ValueParser::<i64>::new().range(..=value.end); |
460 | Self::from(inner) |
461 | } |
462 | } |
463 | |
464 | /// Create an `i64` [`ValueParser`] from a `..` range |
465 | /// |
466 | /// See [`RangedI64ValueParser`] for more control over the output type. |
467 | /// |
468 | /// See also [`RangedU64ValueParser`] |
469 | /// |
470 | /// # Examples |
471 | /// |
472 | /// ```rust |
473 | /// # use clap_builder as clap; |
474 | /// let mut cmd = clap::Command::new("raw" ) |
475 | /// .arg( |
476 | /// clap::Arg::new("port" ) |
477 | /// .long("port" ) |
478 | /// .value_parser(..) |
479 | /// .action(clap::ArgAction::Set) |
480 | /// .required(true) |
481 | /// ); |
482 | /// |
483 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "3001" ]).unwrap(); |
484 | /// let port: i64 = *m.get_one("port" ) |
485 | /// .expect("required" ); |
486 | /// assert_eq!(port, 3001); |
487 | /// ``` |
488 | impl From<std::ops::RangeFull> for ValueParser { |
489 | fn from(value: std::ops::RangeFull) -> Self { |
490 | let inner = RangedI64ValueParser::<i64>::new().range(value); |
491 | Self::from(inner) |
492 | } |
493 | } |
494 | |
495 | /// Create a [`ValueParser`] with [`PossibleValuesParser`] |
496 | /// |
497 | /// See [`PossibleValuesParser`] for more flexibility in creating the |
498 | /// [`PossibleValue`][crate::builder::PossibleValue]s. |
499 | /// |
500 | /// # Examples |
501 | /// |
502 | /// ```rust |
503 | /// # use clap_builder as clap; |
504 | /// let mut cmd = clap::Command::new("raw" ) |
505 | /// .arg( |
506 | /// clap::Arg::new("color" ) |
507 | /// .long("color" ) |
508 | /// .value_parser(["always" , "auto" , "never" ]) |
509 | /// .default_value("auto" ) |
510 | /// ); |
511 | /// |
512 | /// let m = cmd.try_get_matches_from_mut( |
513 | /// ["cmd" , "--color" , "never" ] |
514 | /// ).unwrap(); |
515 | /// |
516 | /// let color: &String = m.get_one("color" ) |
517 | /// .expect("default" ); |
518 | /// assert_eq!(color, "never" ); |
519 | /// ``` |
520 | impl<P, const C: usize> From<[P; C]> for ValueParser |
521 | where |
522 | P: Into<super::PossibleValue>, |
523 | { |
524 | fn from(values: [P; C]) -> Self { |
525 | let inner = PossibleValuesParser::from(values); |
526 | Self::from(inner) |
527 | } |
528 | } |
529 | |
530 | /// Create a [`ValueParser`] with [`PossibleValuesParser`] |
531 | /// |
532 | /// See [`PossibleValuesParser`] for more flexibility in creating the |
533 | /// [`PossibleValue`][crate::builder::PossibleValue]s. |
534 | /// |
535 | /// # Examples |
536 | /// |
537 | /// ```rust |
538 | /// # use clap_builder as clap; |
539 | /// let possible = vec!["always" , "auto" , "never" ]; |
540 | /// let mut cmd = clap::Command::new("raw" ) |
541 | /// .arg( |
542 | /// clap::Arg::new("color" ) |
543 | /// .long("color" ) |
544 | /// .value_parser(possible) |
545 | /// .default_value("auto" ) |
546 | /// ); |
547 | /// |
548 | /// let m = cmd.try_get_matches_from_mut( |
549 | /// ["cmd" , "--color" , "never" ] |
550 | /// ).unwrap(); |
551 | /// |
552 | /// let color: &String = m.get_one("color" ) |
553 | /// .expect("default" ); |
554 | /// assert_eq!(color, "never" ); |
555 | /// ``` |
556 | impl<P> From<Vec<P>> for ValueParser |
557 | where |
558 | P: Into<super::PossibleValue>, |
559 | { |
560 | fn from(values: Vec<P>) -> Self { |
561 | let inner = PossibleValuesParser::from(values); |
562 | Self::from(inner) |
563 | } |
564 | } |
565 | |
566 | impl std::fmt::Debug for ValueParser { |
567 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { |
568 | match &self.0 { |
569 | ValueParserInner::Bool => f.debug_struct("ValueParser::bool" ).finish(), |
570 | ValueParserInner::String => f.debug_struct("ValueParser::string" ).finish(), |
571 | ValueParserInner::OsString => f.debug_struct("ValueParser::os_string" ).finish(), |
572 | ValueParserInner::PathBuf => f.debug_struct("ValueParser::path_buf" ).finish(), |
573 | ValueParserInner::Other(o) => write!(f, "ValueParser::other({:?})" , o.type_id()), |
574 | } |
575 | } |
576 | } |
577 | |
578 | impl Clone for ValueParser { |
579 | fn clone(&self) -> Self { |
580 | Self(match &self.0 { |
581 | ValueParserInner::Bool => ValueParserInner::Bool, |
582 | ValueParserInner::String => ValueParserInner::String, |
583 | ValueParserInner::OsString => ValueParserInner::OsString, |
584 | ValueParserInner::PathBuf => ValueParserInner::PathBuf, |
585 | ValueParserInner::Other(o) => ValueParserInner::Other(o.clone_any()), |
586 | }) |
587 | } |
588 | } |
589 | |
590 | /// A type-erased wrapper for [`TypedValueParser`]. |
591 | trait AnyValueParser: Send + Sync + 'static { |
592 | fn parse_ref( |
593 | &self, |
594 | cmd: &crate::Command, |
595 | arg: Option<&crate::Arg>, |
596 | value: &std::ffi::OsStr, |
597 | ) -> Result<AnyValue, crate::Error>; |
598 | |
599 | fn parse_ref_( |
600 | &self, |
601 | cmd: &crate::Command, |
602 | arg: Option<&crate::Arg>, |
603 | value: &std::ffi::OsStr, |
604 | _source: ValueSource, |
605 | ) -> Result<AnyValue, crate::Error> { |
606 | self.parse_ref(cmd, arg, value) |
607 | } |
608 | |
609 | fn parse( |
610 | &self, |
611 | cmd: &crate::Command, |
612 | arg: Option<&crate::Arg>, |
613 | value: std::ffi::OsString, |
614 | ) -> Result<AnyValue, crate::Error>; |
615 | |
616 | fn parse_( |
617 | &self, |
618 | cmd: &crate::Command, |
619 | arg: Option<&crate::Arg>, |
620 | value: std::ffi::OsString, |
621 | _source: ValueSource, |
622 | ) -> Result<AnyValue, crate::Error> { |
623 | self.parse(cmd, arg, value) |
624 | } |
625 | |
626 | /// Describes the content of `AnyValue` |
627 | fn type_id(&self) -> AnyValueId; |
628 | |
629 | fn possible_values( |
630 | &self, |
631 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>>; |
632 | |
633 | fn clone_any(&self) -> Box<dyn AnyValueParser>; |
634 | } |
635 | |
636 | impl<T, P> AnyValueParser for P |
637 | where |
638 | T: std::any::Any + Clone + Send + Sync + 'static, |
639 | P: TypedValueParser<Value = T>, |
640 | { |
641 | fn parse_ref( |
642 | &self, |
643 | cmd: &crate::Command, |
644 | arg: Option<&crate::Arg>, |
645 | value: &std::ffi::OsStr, |
646 | ) -> Result<AnyValue, crate::Error> { |
647 | let value = ok!(TypedValueParser::parse_ref(self, cmd, arg, value)); |
648 | Ok(AnyValue::new(value)) |
649 | } |
650 | |
651 | fn parse_ref_( |
652 | &self, |
653 | cmd: &crate::Command, |
654 | arg: Option<&crate::Arg>, |
655 | value: &std::ffi::OsStr, |
656 | source: ValueSource, |
657 | ) -> Result<AnyValue, crate::Error> { |
658 | let value = ok!(TypedValueParser::parse_ref_(self, cmd, arg, value, source)); |
659 | Ok(AnyValue::new(value)) |
660 | } |
661 | |
662 | fn parse( |
663 | &self, |
664 | cmd: &crate::Command, |
665 | arg: Option<&crate::Arg>, |
666 | value: std::ffi::OsString, |
667 | ) -> Result<AnyValue, crate::Error> { |
668 | let value = ok!(TypedValueParser::parse(self, cmd, arg, value)); |
669 | Ok(AnyValue::new(value)) |
670 | } |
671 | |
672 | fn parse_( |
673 | &self, |
674 | cmd: &crate::Command, |
675 | arg: Option<&crate::Arg>, |
676 | value: std::ffi::OsString, |
677 | source: ValueSource, |
678 | ) -> Result<AnyValue, crate::Error> { |
679 | let value = ok!(TypedValueParser::parse_(self, cmd, arg, value, source)); |
680 | Ok(AnyValue::new(value)) |
681 | } |
682 | |
683 | fn type_id(&self) -> AnyValueId { |
684 | AnyValueId::of::<T>() |
685 | } |
686 | |
687 | fn possible_values( |
688 | &self, |
689 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
690 | P::possible_values(self) |
691 | } |
692 | |
693 | fn clone_any(&self) -> Box<dyn AnyValueParser> { |
694 | Box::new(self.clone()) |
695 | } |
696 | } |
697 | |
698 | /// Parse/validate argument values |
699 | /// |
700 | /// As alternatives to implementing `TypedValueParser`, |
701 | /// - Use `Fn(&str) -> Result<T, E>` which implements `TypedValueParser` |
702 | /// - [`TypedValueParser::map`] or [`TypedValueParser::try_map`] to adapt an existing `TypedValueParser` |
703 | /// |
704 | /// See `ValueParserFactory` to register `TypedValueParser::Value` with |
705 | /// [`value_parser!`][crate::value_parser]. |
706 | /// |
707 | /// # Example |
708 | /// |
709 | /// ```rust |
710 | /// # #[cfg (feature = "error-context" )] { |
711 | /// # use clap_builder as clap; |
712 | /// # use clap::error::ErrorKind; |
713 | /// # use clap::error::ContextKind; |
714 | /// # use clap::error::ContextValue; |
715 | /// #[derive(Clone)] |
716 | /// struct Custom(u32); |
717 | /// |
718 | /// #[derive(Clone)] |
719 | /// struct CustomValueParser; |
720 | /// |
721 | /// impl clap::builder::TypedValueParser for CustomValueParser { |
722 | /// type Value = Custom; |
723 | /// |
724 | /// fn parse_ref( |
725 | /// &self, |
726 | /// cmd: &clap::Command, |
727 | /// arg: Option<&clap::Arg>, |
728 | /// value: &std::ffi::OsStr, |
729 | /// ) -> Result<Self::Value, clap::Error> { |
730 | /// let inner = clap::value_parser!(u32); |
731 | /// let val = inner.parse_ref(cmd, arg, value)?; |
732 | /// |
733 | /// const INVALID_VALUE: u32 = 10; |
734 | /// if val == INVALID_VALUE { |
735 | /// let mut err = clap::Error::new(ErrorKind::ValueValidation) |
736 | /// .with_cmd(cmd); |
737 | /// if let Some(arg) = arg { |
738 | /// err.insert(ContextKind::InvalidArg, ContextValue::String(arg.to_string())); |
739 | /// } |
740 | /// err.insert(ContextKind::InvalidValue, ContextValue::String(INVALID_VALUE.to_string())); |
741 | /// return Err(err); |
742 | /// } |
743 | /// |
744 | /// Ok(Custom(val)) |
745 | /// } |
746 | /// } |
747 | /// # } |
748 | /// ``` |
749 | pub trait TypedValueParser: Clone + Send + Sync + 'static { |
750 | /// Argument's value type |
751 | type Value: Send + Sync + Clone; |
752 | |
753 | /// Parse the argument value |
754 | /// |
755 | /// When `arg` is `None`, an external subcommand value is being parsed. |
756 | fn parse_ref( |
757 | &self, |
758 | cmd: &crate::Command, |
759 | arg: Option<&crate::Arg>, |
760 | value: &std::ffi::OsStr, |
761 | ) -> Result<Self::Value, crate::Error>; |
762 | |
763 | /// Parse the argument value |
764 | /// |
765 | /// When `arg` is `None`, an external subcommand value is being parsed. |
766 | fn parse_ref_( |
767 | &self, |
768 | cmd: &crate::Command, |
769 | arg: Option<&crate::Arg>, |
770 | value: &std::ffi::OsStr, |
771 | _source: ValueSource, |
772 | ) -> Result<Self::Value, crate::Error> { |
773 | self.parse_ref(cmd, arg, value) |
774 | } |
775 | |
776 | /// Parse the argument value |
777 | /// |
778 | /// When `arg` is `None`, an external subcommand value is being parsed. |
779 | fn parse( |
780 | &self, |
781 | cmd: &crate::Command, |
782 | arg: Option<&crate::Arg>, |
783 | value: std::ffi::OsString, |
784 | ) -> Result<Self::Value, crate::Error> { |
785 | self.parse_ref(cmd, arg, &value) |
786 | } |
787 | |
788 | /// Parse the argument value |
789 | /// |
790 | /// When `arg` is `None`, an external subcommand value is being parsed. |
791 | fn parse_( |
792 | &self, |
793 | cmd: &crate::Command, |
794 | arg: Option<&crate::Arg>, |
795 | value: std::ffi::OsString, |
796 | _source: ValueSource, |
797 | ) -> Result<Self::Value, crate::Error> { |
798 | self.parse(cmd, arg, value) |
799 | } |
800 | |
801 | /// Reflect on enumerated value properties |
802 | /// |
803 | /// Error checking should not be done with this; it is mostly targeted at user-facing |
804 | /// applications like errors and completion. |
805 | fn possible_values( |
806 | &self, |
807 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
808 | None |
809 | } |
810 | |
811 | /// Adapt a `TypedValueParser` from one value to another |
812 | /// |
813 | /// # Example |
814 | /// |
815 | /// ```rust |
816 | /// # use clap_builder as clap; |
817 | /// # use clap::Command; |
818 | /// # use clap::Arg; |
819 | /// # use clap::builder::TypedValueParser as _; |
820 | /// # use clap::builder::BoolishValueParser; |
821 | /// let cmd = Command::new("mycmd" ) |
822 | /// .arg( |
823 | /// Arg::new("flag" ) |
824 | /// .long("flag" ) |
825 | /// .action(clap::ArgAction::SetTrue) |
826 | /// .value_parser( |
827 | /// BoolishValueParser::new() |
828 | /// .map(|b| -> usize { |
829 | /// if b { 10 } else { 5 } |
830 | /// }) |
831 | /// ) |
832 | /// ); |
833 | /// |
834 | /// let matches = cmd.clone().try_get_matches_from(["mycmd" , "--flag" ]).unwrap(); |
835 | /// assert!(matches.contains_id("flag" )); |
836 | /// assert_eq!( |
837 | /// matches.get_one::<usize>("flag" ).copied(), |
838 | /// Some(10) |
839 | /// ); |
840 | /// |
841 | /// let matches = cmd.try_get_matches_from(["mycmd" ]).unwrap(); |
842 | /// assert!(matches.contains_id("flag" )); |
843 | /// assert_eq!( |
844 | /// matches.get_one::<usize>("flag" ).copied(), |
845 | /// Some(5) |
846 | /// ); |
847 | /// ``` |
848 | fn map<T, F>(self, func: F) -> MapValueParser<Self, F> |
849 | where |
850 | T: Send + Sync + Clone, |
851 | F: Fn(Self::Value) -> T + Clone, |
852 | { |
853 | MapValueParser::new(self, func) |
854 | } |
855 | |
856 | /// Adapt a `TypedValueParser` from one value to another |
857 | /// |
858 | /// # Example |
859 | /// |
860 | /// ```rust |
861 | /// # use clap_builder as clap; |
862 | /// # use std::ffi::OsString; |
863 | /// # use std::ffi::OsStr; |
864 | /// # use std::path::PathBuf; |
865 | /// # use std::path::Path; |
866 | /// # use clap::Command; |
867 | /// # use clap::Arg; |
868 | /// # use clap::builder::TypedValueParser as _; |
869 | /// # use clap::builder::OsStringValueParser; |
870 | /// let cmd = Command::new("mycmd" ) |
871 | /// .arg( |
872 | /// Arg::new("flag" ) |
873 | /// .long("flag" ) |
874 | /// .value_parser( |
875 | /// OsStringValueParser::new() |
876 | /// .try_map(verify_ext) |
877 | /// ) |
878 | /// ); |
879 | /// |
880 | /// fn verify_ext(os: OsString) -> Result<PathBuf, &'static str> { |
881 | /// let path = PathBuf::from(os); |
882 | /// if path.extension() != Some(OsStr::new("rs" )) { |
883 | /// return Err("only Rust files are supported" ); |
884 | /// } |
885 | /// Ok(path) |
886 | /// } |
887 | /// |
888 | /// let error = cmd.clone().try_get_matches_from(["mycmd" , "--flag" , "foo.txt" ]).unwrap_err(); |
889 | /// error.print(); |
890 | /// |
891 | /// let matches = cmd.try_get_matches_from(["mycmd" , "--flag" , "foo.rs" ]).unwrap(); |
892 | /// assert!(matches.contains_id("flag" )); |
893 | /// assert_eq!( |
894 | /// matches.get_one::<PathBuf>("flag" ).map(|s| s.as_path()), |
895 | /// Some(Path::new("foo.rs" )) |
896 | /// ); |
897 | /// ``` |
898 | fn try_map<T, E, F>(self, func: F) -> TryMapValueParser<Self, F> |
899 | where |
900 | F: Fn(Self::Value) -> Result<T, E> + Clone + Send + Sync + 'static, |
901 | T: Send + Sync + Clone, |
902 | E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
903 | { |
904 | TryMapValueParser::new(self, func) |
905 | } |
906 | } |
907 | |
908 | impl<F, T, E> TypedValueParser for F |
909 | where |
910 | F: Fn(&str) -> Result<T, E> + Clone + Send + Sync + 'static, |
911 | E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
912 | T: Send + Sync + Clone, |
913 | { |
914 | type Value = T; |
915 | |
916 | fn parse_ref( |
917 | &self, |
918 | cmd: &crate::Command, |
919 | arg: Option<&crate::Arg>, |
920 | value: &std::ffi::OsStr, |
921 | ) -> Result<Self::Value, crate::Error> { |
922 | let value = ok!(value.to_str().ok_or_else(|| { |
923 | crate::Error::invalid_utf8( |
924 | cmd, |
925 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
926 | ) |
927 | })); |
928 | let value = ok!((self)(value).map_err(|e| { |
929 | let arg = arg |
930 | .map(|a| a.to_string()) |
931 | .unwrap_or_else(|| "..." .to_owned()); |
932 | crate::Error::value_validation(arg, value.to_owned(), e.into()).with_cmd(cmd) |
933 | })); |
934 | Ok(value) |
935 | } |
936 | } |
937 | |
938 | /// Implementation for [`ValueParser::string`] |
939 | /// |
940 | /// Useful for composing new [`TypedValueParser`]s |
941 | #[derive(Copy, Clone, Debug)] |
942 | #[non_exhaustive ] |
943 | pub struct StringValueParser {} |
944 | |
945 | impl StringValueParser { |
946 | /// Implementation for [`ValueParser::string`] |
947 | pub fn new() -> Self { |
948 | Self {} |
949 | } |
950 | } |
951 | |
952 | impl TypedValueParser for StringValueParser { |
953 | type Value = String; |
954 | |
955 | fn parse_ref( |
956 | &self, |
957 | cmd: &crate::Command, |
958 | arg: Option<&crate::Arg>, |
959 | value: &std::ffi::OsStr, |
960 | ) -> Result<Self::Value, crate::Error> { |
961 | TypedValueParser::parse(self, cmd, arg, value.to_owned()) |
962 | } |
963 | |
964 | fn parse( |
965 | &self, |
966 | cmd: &crate::Command, |
967 | _arg: Option<&crate::Arg>, |
968 | value: std::ffi::OsString, |
969 | ) -> Result<Self::Value, crate::Error> { |
970 | let value = ok!(value.into_string().map_err(|_| { |
971 | crate::Error::invalid_utf8( |
972 | cmd, |
973 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
974 | ) |
975 | })); |
976 | Ok(value) |
977 | } |
978 | } |
979 | |
980 | impl Default for StringValueParser { |
981 | fn default() -> Self { |
982 | Self::new() |
983 | } |
984 | } |
985 | |
986 | /// Implementation for [`ValueParser::os_string`] |
987 | /// |
988 | /// Useful for composing new [`TypedValueParser`]s |
989 | #[derive(Copy, Clone, Debug)] |
990 | #[non_exhaustive ] |
991 | pub struct OsStringValueParser {} |
992 | |
993 | impl OsStringValueParser { |
994 | /// Implementation for [`ValueParser::os_string`] |
995 | pub fn new() -> Self { |
996 | Self {} |
997 | } |
998 | } |
999 | |
1000 | impl TypedValueParser for OsStringValueParser { |
1001 | type Value = std::ffi::OsString; |
1002 | |
1003 | fn parse_ref( |
1004 | &self, |
1005 | cmd: &crate::Command, |
1006 | arg: Option<&crate::Arg>, |
1007 | value: &std::ffi::OsStr, |
1008 | ) -> Result<Self::Value, crate::Error> { |
1009 | TypedValueParser::parse(self, cmd, arg, value.to_owned()) |
1010 | } |
1011 | |
1012 | fn parse( |
1013 | &self, |
1014 | _cmd: &crate::Command, |
1015 | _arg: Option<&crate::Arg>, |
1016 | value: std::ffi::OsString, |
1017 | ) -> Result<Self::Value, crate::Error> { |
1018 | Ok(value) |
1019 | } |
1020 | } |
1021 | |
1022 | impl Default for OsStringValueParser { |
1023 | fn default() -> Self { |
1024 | Self::new() |
1025 | } |
1026 | } |
1027 | |
1028 | /// Implementation for [`ValueParser::path_buf`] |
1029 | /// |
1030 | /// Useful for composing new [`TypedValueParser`]s |
1031 | #[derive(Copy, Clone, Debug)] |
1032 | #[non_exhaustive ] |
1033 | pub struct PathBufValueParser {} |
1034 | |
1035 | impl PathBufValueParser { |
1036 | /// Implementation for [`ValueParser::path_buf`] |
1037 | pub fn new() -> Self { |
1038 | Self {} |
1039 | } |
1040 | } |
1041 | |
1042 | impl TypedValueParser for PathBufValueParser { |
1043 | type Value = std::path::PathBuf; |
1044 | |
1045 | fn parse_ref( |
1046 | &self, |
1047 | cmd: &crate::Command, |
1048 | arg: Option<&crate::Arg>, |
1049 | value: &std::ffi::OsStr, |
1050 | ) -> Result<Self::Value, crate::Error> { |
1051 | TypedValueParser::parse(self, cmd, arg, value.to_owned()) |
1052 | } |
1053 | |
1054 | fn parse( |
1055 | &self, |
1056 | cmd: &crate::Command, |
1057 | arg: Option<&crate::Arg>, |
1058 | value: std::ffi::OsString, |
1059 | ) -> Result<Self::Value, crate::Error> { |
1060 | if value.is_empty() { |
1061 | return Err(crate::Error::empty_value( |
1062 | cmd, |
1063 | &[], |
1064 | arg.map(ToString::to_string) |
1065 | .unwrap_or_else(|| "..." .to_owned()), |
1066 | )); |
1067 | } |
1068 | Ok(Self::Value::from(value)) |
1069 | } |
1070 | } |
1071 | |
1072 | impl Default for PathBufValueParser { |
1073 | fn default() -> Self { |
1074 | Self::new() |
1075 | } |
1076 | } |
1077 | |
1078 | /// Parse an [`ValueEnum`][crate::ValueEnum] value. |
1079 | /// |
1080 | /// See also: |
1081 | /// - [`PossibleValuesParser`] |
1082 | /// |
1083 | /// # Example |
1084 | /// |
1085 | /// ```rust |
1086 | /// # use clap_builder as clap; |
1087 | /// # use std::ffi::OsStr; |
1088 | /// # use clap::ColorChoice; |
1089 | /// # use clap::builder::TypedValueParser; |
1090 | /// # let cmd = clap::Command::new("test" ); |
1091 | /// # let arg = None; |
1092 | /// |
1093 | /// // Usage |
1094 | /// let mut cmd = clap::Command::new("raw" ) |
1095 | /// .arg( |
1096 | /// clap::Arg::new("color" ) |
1097 | /// .value_parser(clap::builder::EnumValueParser::<ColorChoice>::new()) |
1098 | /// .required(true) |
1099 | /// ); |
1100 | /// |
1101 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "always" ]).unwrap(); |
1102 | /// let port: ColorChoice = *m.get_one("color" ) |
1103 | /// .expect("required" ); |
1104 | /// assert_eq!(port, ColorChoice::Always); |
1105 | /// |
1106 | /// // Semantics |
1107 | /// let value_parser = clap::builder::EnumValueParser::<ColorChoice>::new(); |
1108 | /// // or |
1109 | /// let value_parser = clap::value_parser!(ColorChoice); |
1110 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1111 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1112 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("always" )).unwrap(), ColorChoice::Always); |
1113 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("auto" )).unwrap(), ColorChoice::Auto); |
1114 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("never" )).unwrap(), ColorChoice::Never); |
1115 | /// ``` |
1116 | #[derive(Clone, Debug)] |
1117 | pub struct EnumValueParser<E: crate::ValueEnum + Clone + Send + Sync + 'static>( |
1118 | std::marker::PhantomData<E>, |
1119 | ); |
1120 | |
1121 | impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> EnumValueParser<E> { |
1122 | /// Parse an [`ValueEnum`][crate::ValueEnum] |
1123 | pub fn new() -> Self { |
1124 | let phantom: std::marker::PhantomData<E> = Default::default(); |
1125 | Self(phantom) |
1126 | } |
1127 | } |
1128 | |
1129 | impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> TypedValueParser for EnumValueParser<E> { |
1130 | type Value = E; |
1131 | |
1132 | fn parse_ref( |
1133 | &self, |
1134 | cmd: &crate::Command, |
1135 | arg: Option<&crate::Arg>, |
1136 | value: &std::ffi::OsStr, |
1137 | ) -> Result<Self::Value, crate::Error> { |
1138 | let ignore_case = arg.map(|a| a.is_ignore_case_set()).unwrap_or(false); |
1139 | let possible_vals = || { |
1140 | E::value_variants() |
1141 | .iter() |
1142 | .filter_map(|v| v.to_possible_value()) |
1143 | .filter(|v| !v.is_hide_set()) |
1144 | .map(|v| v.get_name().to_owned()) |
1145 | .collect::<Vec<_>>() |
1146 | }; |
1147 | |
1148 | let value = ok!(value.to_str().ok_or_else(|| { |
1149 | crate::Error::invalid_value( |
1150 | cmd, |
1151 | value.to_string_lossy().into_owned(), |
1152 | &possible_vals(), |
1153 | arg.map(ToString::to_string) |
1154 | .unwrap_or_else(|| "..." .to_owned()), |
1155 | ) |
1156 | })); |
1157 | let value = ok!(E::value_variants() |
1158 | .iter() |
1159 | .find(|v| { |
1160 | v.to_possible_value() |
1161 | .expect("ValueEnum::value_variants contains only values with a corresponding ValueEnum::to_possible_value" ) |
1162 | .matches(value, ignore_case) |
1163 | }) |
1164 | .ok_or_else(|| { |
1165 | crate::Error::invalid_value( |
1166 | cmd, |
1167 | value.to_owned(), |
1168 | &possible_vals(), |
1169 | arg.map(ToString::to_string) |
1170 | .unwrap_or_else(|| "..." .to_owned()), |
1171 | ) |
1172 | })) |
1173 | .clone(); |
1174 | Ok(value) |
1175 | } |
1176 | |
1177 | fn possible_values( |
1178 | &self, |
1179 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1180 | Some(Box::new( |
1181 | E::value_variants() |
1182 | .iter() |
1183 | .filter_map(|v| v.to_possible_value()), |
1184 | )) |
1185 | } |
1186 | } |
1187 | |
1188 | impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> Default for EnumValueParser<E> { |
1189 | fn default() -> Self { |
1190 | Self::new() |
1191 | } |
1192 | } |
1193 | |
1194 | /// Verify the value is from an enumerated set of [`PossibleValue`][crate::builder::PossibleValue]. |
1195 | /// |
1196 | /// See also: |
1197 | /// - [`EnumValueParser`] for directly supporting [`ValueEnum`][crate::ValueEnum] types |
1198 | /// - [`TypedValueParser::map`] for adapting values to a more specialized type, like an external |
1199 | /// enums that can't implement [`ValueEnum`][crate::ValueEnum] |
1200 | /// |
1201 | /// # Example |
1202 | /// |
1203 | /// Usage: |
1204 | /// ```rust |
1205 | /// # use clap_builder as clap; |
1206 | /// let mut cmd = clap::Command::new("raw" ) |
1207 | /// .arg( |
1208 | /// clap::Arg::new("color" ) |
1209 | /// .value_parser(clap::builder::PossibleValuesParser::new(["always" , "auto" , "never" ])) |
1210 | /// .required(true) |
1211 | /// ); |
1212 | /// |
1213 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "always" ]).unwrap(); |
1214 | /// let port: &String = m.get_one("color" ) |
1215 | /// .expect("required" ); |
1216 | /// assert_eq!(port, "always" ); |
1217 | /// ``` |
1218 | /// |
1219 | /// Semantics: |
1220 | /// ```rust |
1221 | /// # use clap_builder as clap; |
1222 | /// # use std::ffi::OsStr; |
1223 | /// # use clap::builder::TypedValueParser; |
1224 | /// # let cmd = clap::Command::new("test" ); |
1225 | /// # let arg = None; |
1226 | /// let value_parser = clap::builder::PossibleValuesParser::new(["always" , "auto" , "never" ]); |
1227 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1228 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1229 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("always" )).unwrap(), "always" ); |
1230 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("auto" )).unwrap(), "auto" ); |
1231 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("never" )).unwrap(), "never" ); |
1232 | /// ``` |
1233 | #[derive(Clone, Debug)] |
1234 | pub struct PossibleValuesParser(Vec<super::PossibleValue>); |
1235 | |
1236 | impl PossibleValuesParser { |
1237 | /// Verify the value is from an enumerated set of [`PossibleValue`][crate::builder::PossibleValue]. |
1238 | pub fn new(values: impl Into<PossibleValuesParser>) -> Self { |
1239 | values.into() |
1240 | } |
1241 | } |
1242 | |
1243 | impl TypedValueParser for PossibleValuesParser { |
1244 | type Value = String; |
1245 | |
1246 | fn parse_ref( |
1247 | &self, |
1248 | cmd: &crate::Command, |
1249 | arg: Option<&crate::Arg>, |
1250 | value: &std::ffi::OsStr, |
1251 | ) -> Result<Self::Value, crate::Error> { |
1252 | TypedValueParser::parse(self, cmd, arg, value.to_owned()) |
1253 | } |
1254 | |
1255 | fn parse( |
1256 | &self, |
1257 | cmd: &crate::Command, |
1258 | arg: Option<&crate::Arg>, |
1259 | value: std::ffi::OsString, |
1260 | ) -> Result<String, crate::Error> { |
1261 | let value = ok!(value.into_string().map_err(|_| { |
1262 | crate::Error::invalid_utf8( |
1263 | cmd, |
1264 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1265 | ) |
1266 | })); |
1267 | |
1268 | let ignore_case = arg.map(|a| a.is_ignore_case_set()).unwrap_or(false); |
1269 | if self.0.iter().any(|v| v.matches(&value, ignore_case)) { |
1270 | Ok(value) |
1271 | } else { |
1272 | let possible_vals = self |
1273 | .0 |
1274 | .iter() |
1275 | .filter(|v| !v.is_hide_set()) |
1276 | .map(|v| v.get_name().to_owned()) |
1277 | .collect::<Vec<_>>(); |
1278 | |
1279 | Err(crate::Error::invalid_value( |
1280 | cmd, |
1281 | value, |
1282 | &possible_vals, |
1283 | arg.map(ToString::to_string) |
1284 | .unwrap_or_else(|| "..." .to_owned()), |
1285 | )) |
1286 | } |
1287 | } |
1288 | |
1289 | fn possible_values( |
1290 | &self, |
1291 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1292 | Some(Box::new(self.0.iter().cloned())) |
1293 | } |
1294 | } |
1295 | |
1296 | impl<I, T> From<I> for PossibleValuesParser |
1297 | where |
1298 | I: IntoIterator<Item = T>, |
1299 | T: Into<super::PossibleValue>, |
1300 | { |
1301 | fn from(values: I) -> Self { |
1302 | Self(values.into_iter().map(|t| t.into()).collect()) |
1303 | } |
1304 | } |
1305 | |
1306 | /// Parse number that fall within a range of values |
1307 | /// |
1308 | /// **NOTE:** To capture negative values, you will also need to set |
1309 | /// [`Arg::allow_negative_numbers`][crate::Arg::allow_negative_numbers] or |
1310 | /// [`Arg::allow_hyphen_values`][crate::Arg::allow_hyphen_values]. |
1311 | /// |
1312 | /// # Example |
1313 | /// |
1314 | /// Usage: |
1315 | /// ```rust |
1316 | /// # use clap_builder as clap; |
1317 | /// let mut cmd = clap::Command::new("raw" ) |
1318 | /// .arg( |
1319 | /// clap::Arg::new("port" ) |
1320 | /// .long("port" ) |
1321 | /// .value_parser(clap::value_parser!(u16).range(3000..)) |
1322 | /// .action(clap::ArgAction::Set) |
1323 | /// .required(true) |
1324 | /// ); |
1325 | /// |
1326 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "3001" ]).unwrap(); |
1327 | /// let port: u16 = *m.get_one("port" ) |
1328 | /// .expect("required" ); |
1329 | /// assert_eq!(port, 3001); |
1330 | /// ``` |
1331 | /// |
1332 | /// Semantics: |
1333 | /// ```rust |
1334 | /// # use clap_builder as clap; |
1335 | /// # use std::ffi::OsStr; |
1336 | /// # use clap::builder::TypedValueParser; |
1337 | /// # let cmd = clap::Command::new("test" ); |
1338 | /// # let arg = None; |
1339 | /// let value_parser = clap::builder::RangedI64ValueParser::<i32>::new().range(-1..200); |
1340 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1341 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1342 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-200" )).is_err()); |
1343 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("300" )).is_err()); |
1344 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("-1" )).unwrap(), -1); |
1345 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0" )).unwrap(), 0); |
1346 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50" )).unwrap(), 50); |
1347 | /// ``` |
1348 | #[derive(Copy, Clone, Debug)] |
1349 | pub struct RangedI64ValueParser<T: std::convert::TryFrom<i64> + Clone + Send + Sync = i64> { |
1350 | bounds: (std::ops::Bound<i64>, std::ops::Bound<i64>), |
1351 | target: std::marker::PhantomData<T>, |
1352 | } |
1353 | |
1354 | impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync> RangedI64ValueParser<T> { |
1355 | /// Select full range of `i64` |
1356 | pub fn new() -> Self { |
1357 | Self::from(..) |
1358 | } |
1359 | |
1360 | /// Narrow the supported range |
1361 | pub fn range<B: RangeBounds<i64>>(mut self, range: B) -> Self { |
1362 | // Consideration: when the user does `value_parser!(u8).range()` |
1363 | // - Avoid programming mistakes by accidentally expanding the range |
1364 | // - Make it convenient to limit the range like with `..10` |
1365 | let start = match range.start_bound() { |
1366 | l @ std::ops::Bound::Included(i) => { |
1367 | debug_assert!( |
1368 | self.bounds.contains(i), |
1369 | "{} must be in {:?}" , |
1370 | i, |
1371 | self.bounds |
1372 | ); |
1373 | l.cloned() |
1374 | } |
1375 | l @ std::ops::Bound::Excluded(i) => { |
1376 | debug_assert!( |
1377 | self.bounds.contains(&i.saturating_add(1)), |
1378 | "{} must be in {:?}" , |
1379 | i, |
1380 | self.bounds |
1381 | ); |
1382 | l.cloned() |
1383 | } |
1384 | std::ops::Bound::Unbounded => self.bounds.start_bound().cloned(), |
1385 | }; |
1386 | let end = match range.end_bound() { |
1387 | l @ std::ops::Bound::Included(i) => { |
1388 | debug_assert!( |
1389 | self.bounds.contains(i), |
1390 | "{} must be in {:?}" , |
1391 | i, |
1392 | self.bounds |
1393 | ); |
1394 | l.cloned() |
1395 | } |
1396 | l @ std::ops::Bound::Excluded(i) => { |
1397 | debug_assert!( |
1398 | self.bounds.contains(&i.saturating_sub(1)), |
1399 | "{} must be in {:?}" , |
1400 | i, |
1401 | self.bounds |
1402 | ); |
1403 | l.cloned() |
1404 | } |
1405 | std::ops::Bound::Unbounded => self.bounds.end_bound().cloned(), |
1406 | }; |
1407 | self.bounds = (start, end); |
1408 | self |
1409 | } |
1410 | |
1411 | fn format_bounds(&self) -> String { |
1412 | let mut result = match self.bounds.0 { |
1413 | std::ops::Bound::Included(i) => i.to_string(), |
1414 | std::ops::Bound::Excluded(i) => i.saturating_add(1).to_string(), |
1415 | std::ops::Bound::Unbounded => i64::MIN.to_string(), |
1416 | }; |
1417 | result.push_str(".." ); |
1418 | match self.bounds.1 { |
1419 | std::ops::Bound::Included(i) => { |
1420 | result.push('=' ); |
1421 | result.push_str(&i.to_string()); |
1422 | } |
1423 | std::ops::Bound::Excluded(i) => { |
1424 | result.push_str(&i.to_string()); |
1425 | } |
1426 | std::ops::Bound::Unbounded => { |
1427 | result.push_str(&i64::MAX.to_string()); |
1428 | } |
1429 | } |
1430 | result |
1431 | } |
1432 | } |
1433 | |
1434 | impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync + 'static> TypedValueParser |
1435 | for RangedI64ValueParser<T> |
1436 | where |
1437 | <T as std::convert::TryFrom<i64>>::Error: Send + Sync + 'static + std::error::Error + ToString, |
1438 | { |
1439 | type Value = T; |
1440 | |
1441 | fn parse_ref( |
1442 | &self, |
1443 | cmd: &crate::Command, |
1444 | arg: Option<&crate::Arg>, |
1445 | raw_value: &std::ffi::OsStr, |
1446 | ) -> Result<Self::Value, crate::Error> { |
1447 | let value = ok!(raw_value.to_str().ok_or_else(|| { |
1448 | crate::Error::invalid_utf8( |
1449 | cmd, |
1450 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1451 | ) |
1452 | })); |
1453 | let value = ok!(value.parse::<i64>().map_err(|err| { |
1454 | let arg = arg |
1455 | .map(|a| a.to_string()) |
1456 | .unwrap_or_else(|| "..." .to_owned()); |
1457 | crate::Error::value_validation( |
1458 | arg, |
1459 | raw_value.to_string_lossy().into_owned(), |
1460 | err.into(), |
1461 | ) |
1462 | .with_cmd(cmd) |
1463 | })); |
1464 | if !self.bounds.contains(&value) { |
1465 | let arg = arg |
1466 | .map(|a| a.to_string()) |
1467 | .unwrap_or_else(|| "..." .to_owned()); |
1468 | return Err(crate::Error::value_validation( |
1469 | arg, |
1470 | raw_value.to_string_lossy().into_owned(), |
1471 | format!("{} is not in {}" , value, self.format_bounds()).into(), |
1472 | ) |
1473 | .with_cmd(cmd)); |
1474 | } |
1475 | |
1476 | let value: Result<Self::Value, _> = value.try_into(); |
1477 | let value = ok!(value.map_err(|err| { |
1478 | let arg = arg |
1479 | .map(|a| a.to_string()) |
1480 | .unwrap_or_else(|| "..." .to_owned()); |
1481 | crate::Error::value_validation( |
1482 | arg, |
1483 | raw_value.to_string_lossy().into_owned(), |
1484 | err.into(), |
1485 | ) |
1486 | .with_cmd(cmd) |
1487 | })); |
1488 | |
1489 | Ok(value) |
1490 | } |
1491 | } |
1492 | |
1493 | impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync, B: RangeBounds<i64>> From<B> |
1494 | for RangedI64ValueParser<T> |
1495 | { |
1496 | fn from(range: B) -> Self { |
1497 | Self { |
1498 | bounds: (range.start_bound().cloned(), range.end_bound().cloned()), |
1499 | target: Default::default(), |
1500 | } |
1501 | } |
1502 | } |
1503 | |
1504 | impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync> Default for RangedI64ValueParser<T> { |
1505 | fn default() -> Self { |
1506 | Self::new() |
1507 | } |
1508 | } |
1509 | |
1510 | /// Parse number that fall within a range of values |
1511 | /// |
1512 | /// # Example |
1513 | /// |
1514 | /// Usage: |
1515 | /// ```rust |
1516 | /// # use clap_builder as clap; |
1517 | /// let mut cmd = clap::Command::new("raw" ) |
1518 | /// .arg( |
1519 | /// clap::Arg::new("port" ) |
1520 | /// .long("port" ) |
1521 | /// .value_parser(clap::value_parser!(u64).range(3000..)) |
1522 | /// .action(clap::ArgAction::Set) |
1523 | /// .required(true) |
1524 | /// ); |
1525 | /// |
1526 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "3001" ]).unwrap(); |
1527 | /// let port: u64 = *m.get_one("port" ) |
1528 | /// .expect("required" ); |
1529 | /// assert_eq!(port, 3001); |
1530 | /// ``` |
1531 | /// |
1532 | /// Semantics: |
1533 | /// ```rust |
1534 | /// # use clap_builder as clap; |
1535 | /// # use std::ffi::OsStr; |
1536 | /// # use clap::builder::TypedValueParser; |
1537 | /// # let cmd = clap::Command::new("test" ); |
1538 | /// # let arg = None; |
1539 | /// let value_parser = clap::builder::RangedU64ValueParser::<u32>::new().range(0..200); |
1540 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1541 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1542 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-200" )).is_err()); |
1543 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("300" )).is_err()); |
1544 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-1" )).is_err()); |
1545 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0" )).unwrap(), 0); |
1546 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50" )).unwrap(), 50); |
1547 | /// ``` |
1548 | #[derive(Copy, Clone, Debug)] |
1549 | pub struct RangedU64ValueParser<T: std::convert::TryFrom<u64> = u64> { |
1550 | bounds: (std::ops::Bound<u64>, std::ops::Bound<u64>), |
1551 | target: std::marker::PhantomData<T>, |
1552 | } |
1553 | |
1554 | impl<T: std::convert::TryFrom<u64>> RangedU64ValueParser<T> { |
1555 | /// Select full range of `u64` |
1556 | pub fn new() -> Self { |
1557 | Self::from(..) |
1558 | } |
1559 | |
1560 | /// Narrow the supported range |
1561 | pub fn range<B: RangeBounds<u64>>(mut self, range: B) -> Self { |
1562 | // Consideration: when the user does `value_parser!(u8).range()` |
1563 | // - Avoid programming mistakes by accidentally expanding the range |
1564 | // - Make it convenient to limit the range like with `..10` |
1565 | let start = match range.start_bound() { |
1566 | l @ std::ops::Bound::Included(i) => { |
1567 | debug_assert!( |
1568 | self.bounds.contains(i), |
1569 | "{} must be in {:?}" , |
1570 | i, |
1571 | self.bounds |
1572 | ); |
1573 | l.cloned() |
1574 | } |
1575 | l @ std::ops::Bound::Excluded(i) => { |
1576 | debug_assert!( |
1577 | self.bounds.contains(&i.saturating_add(1)), |
1578 | "{} must be in {:?}" , |
1579 | i, |
1580 | self.bounds |
1581 | ); |
1582 | l.cloned() |
1583 | } |
1584 | std::ops::Bound::Unbounded => self.bounds.start_bound().cloned(), |
1585 | }; |
1586 | let end = match range.end_bound() { |
1587 | l @ std::ops::Bound::Included(i) => { |
1588 | debug_assert!( |
1589 | self.bounds.contains(i), |
1590 | "{} must be in {:?}" , |
1591 | i, |
1592 | self.bounds |
1593 | ); |
1594 | l.cloned() |
1595 | } |
1596 | l @ std::ops::Bound::Excluded(i) => { |
1597 | debug_assert!( |
1598 | self.bounds.contains(&i.saturating_sub(1)), |
1599 | "{} must be in {:?}" , |
1600 | i, |
1601 | self.bounds |
1602 | ); |
1603 | l.cloned() |
1604 | } |
1605 | std::ops::Bound::Unbounded => self.bounds.end_bound().cloned(), |
1606 | }; |
1607 | self.bounds = (start, end); |
1608 | self |
1609 | } |
1610 | |
1611 | fn format_bounds(&self) -> String { |
1612 | let mut result = match self.bounds.0 { |
1613 | std::ops::Bound::Included(i) => i.to_string(), |
1614 | std::ops::Bound::Excluded(i) => i.saturating_add(1).to_string(), |
1615 | std::ops::Bound::Unbounded => u64::MIN.to_string(), |
1616 | }; |
1617 | result.push_str(".." ); |
1618 | match self.bounds.1 { |
1619 | std::ops::Bound::Included(i) => { |
1620 | result.push('=' ); |
1621 | result.push_str(&i.to_string()); |
1622 | } |
1623 | std::ops::Bound::Excluded(i) => { |
1624 | result.push_str(&i.to_string()); |
1625 | } |
1626 | std::ops::Bound::Unbounded => { |
1627 | result.push_str(&u64::MAX.to_string()); |
1628 | } |
1629 | } |
1630 | result |
1631 | } |
1632 | } |
1633 | |
1634 | impl<T: std::convert::TryFrom<u64> + Clone + Send + Sync + 'static> TypedValueParser |
1635 | for RangedU64ValueParser<T> |
1636 | where |
1637 | <T as std::convert::TryFrom<u64>>::Error: Send + Sync + 'static + std::error::Error + ToString, |
1638 | { |
1639 | type Value = T; |
1640 | |
1641 | fn parse_ref( |
1642 | &self, |
1643 | cmd: &crate::Command, |
1644 | arg: Option<&crate::Arg>, |
1645 | raw_value: &std::ffi::OsStr, |
1646 | ) -> Result<Self::Value, crate::Error> { |
1647 | let value = ok!(raw_value.to_str().ok_or_else(|| { |
1648 | crate::Error::invalid_utf8( |
1649 | cmd, |
1650 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1651 | ) |
1652 | })); |
1653 | let value = ok!(value.parse::<u64>().map_err(|err| { |
1654 | let arg = arg |
1655 | .map(|a| a.to_string()) |
1656 | .unwrap_or_else(|| "..." .to_owned()); |
1657 | crate::Error::value_validation( |
1658 | arg, |
1659 | raw_value.to_string_lossy().into_owned(), |
1660 | err.into(), |
1661 | ) |
1662 | .with_cmd(cmd) |
1663 | })); |
1664 | if !self.bounds.contains(&value) { |
1665 | let arg = arg |
1666 | .map(|a| a.to_string()) |
1667 | .unwrap_or_else(|| "..." .to_owned()); |
1668 | return Err(crate::Error::value_validation( |
1669 | arg, |
1670 | raw_value.to_string_lossy().into_owned(), |
1671 | format!("{} is not in {}" , value, self.format_bounds()).into(), |
1672 | ) |
1673 | .with_cmd(cmd)); |
1674 | } |
1675 | |
1676 | let value: Result<Self::Value, _> = value.try_into(); |
1677 | let value = ok!(value.map_err(|err| { |
1678 | let arg = arg |
1679 | .map(|a| a.to_string()) |
1680 | .unwrap_or_else(|| "..." .to_owned()); |
1681 | crate::Error::value_validation( |
1682 | arg, |
1683 | raw_value.to_string_lossy().into_owned(), |
1684 | err.into(), |
1685 | ) |
1686 | .with_cmd(cmd) |
1687 | })); |
1688 | |
1689 | Ok(value) |
1690 | } |
1691 | } |
1692 | |
1693 | impl<T: std::convert::TryFrom<u64>, B: RangeBounds<u64>> From<B> for RangedU64ValueParser<T> { |
1694 | fn from(range: B) -> Self { |
1695 | Self { |
1696 | bounds: (range.start_bound().cloned(), range.end_bound().cloned()), |
1697 | target: Default::default(), |
1698 | } |
1699 | } |
1700 | } |
1701 | |
1702 | impl<T: std::convert::TryFrom<u64>> Default for RangedU64ValueParser<T> { |
1703 | fn default() -> Self { |
1704 | Self::new() |
1705 | } |
1706 | } |
1707 | |
1708 | /// Implementation for [`ValueParser::bool`] |
1709 | /// |
1710 | /// Useful for composing new [`TypedValueParser`]s |
1711 | #[derive(Copy, Clone, Debug)] |
1712 | #[non_exhaustive ] |
1713 | pub struct BoolValueParser {} |
1714 | |
1715 | impl BoolValueParser { |
1716 | /// Implementation for [`ValueParser::bool`] |
1717 | pub fn new() -> Self { |
1718 | Self {} |
1719 | } |
1720 | |
1721 | fn possible_values() -> impl Iterator<Item = crate::builder::PossibleValue> { |
1722 | ["true" , "false" ] |
1723 | .iter() |
1724 | .copied() |
1725 | .map(crate::builder::PossibleValue::new) |
1726 | } |
1727 | } |
1728 | |
1729 | impl TypedValueParser for BoolValueParser { |
1730 | type Value = bool; |
1731 | |
1732 | fn parse_ref( |
1733 | &self, |
1734 | cmd: &crate::Command, |
1735 | arg: Option<&crate::Arg>, |
1736 | value: &std::ffi::OsStr, |
1737 | ) -> Result<Self::Value, crate::Error> { |
1738 | let value = if value == std::ffi::OsStr::new("true" ) { |
1739 | true |
1740 | } else if value == std::ffi::OsStr::new("false" ) { |
1741 | false |
1742 | } else { |
1743 | // Intentionally showing hidden as we hide all of them |
1744 | let possible_vals = Self::possible_values() |
1745 | .map(|v| v.get_name().to_owned()) |
1746 | .collect::<Vec<_>>(); |
1747 | |
1748 | return Err(crate::Error::invalid_value( |
1749 | cmd, |
1750 | value.to_string_lossy().into_owned(), |
1751 | &possible_vals, |
1752 | arg.map(ToString::to_string) |
1753 | .unwrap_or_else(|| "..." .to_owned()), |
1754 | )); |
1755 | }; |
1756 | Ok(value) |
1757 | } |
1758 | |
1759 | fn possible_values( |
1760 | &self, |
1761 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1762 | Some(Box::new(Self::possible_values())) |
1763 | } |
1764 | } |
1765 | |
1766 | impl Default for BoolValueParser { |
1767 | fn default() -> Self { |
1768 | Self::new() |
1769 | } |
1770 | } |
1771 | |
1772 | /// Parse false-like string values, everything else is `true` |
1773 | /// |
1774 | /// See also: |
1775 | /// - [`ValueParser::bool`] for assuming non-false is true |
1776 | /// - [`BoolishValueParser`] for different human readable bool representations |
1777 | /// |
1778 | /// # Example |
1779 | /// |
1780 | /// Usage: |
1781 | /// ```rust |
1782 | /// # use clap_builder as clap; |
1783 | /// let mut cmd = clap::Command::new("raw" ) |
1784 | /// .arg( |
1785 | /// clap::Arg::new("append" ) |
1786 | /// .value_parser(clap::builder::FalseyValueParser::new()) |
1787 | /// .required(true) |
1788 | /// ); |
1789 | /// |
1790 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "true" ]).unwrap(); |
1791 | /// let port: bool = *m.get_one("append" ) |
1792 | /// .expect("required" ); |
1793 | /// assert_eq!(port, true); |
1794 | /// ``` |
1795 | /// |
1796 | /// Semantics: |
1797 | /// ```rust |
1798 | /// # use clap_builder as clap; |
1799 | /// # use std::ffi::OsStr; |
1800 | /// # use clap::builder::TypedValueParser; |
1801 | /// # let cmd = clap::Command::new("test" ); |
1802 | /// # let arg = None; |
1803 | /// let value_parser = clap::builder::FalseyValueParser::new(); |
1804 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).unwrap(), true); |
1805 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("100" )).unwrap(), true); |
1806 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).unwrap(), false); |
1807 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("false" )).unwrap(), false); |
1808 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("No" )).unwrap(), false); |
1809 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oFF" )).unwrap(), false); |
1810 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0" )).unwrap(), false); |
1811 | /// ``` |
1812 | #[derive(Copy, Clone, Debug)] |
1813 | #[non_exhaustive ] |
1814 | pub struct FalseyValueParser {} |
1815 | |
1816 | impl FalseyValueParser { |
1817 | /// Parse false-like string values, everything else is `true` |
1818 | pub fn new() -> Self { |
1819 | Self {} |
1820 | } |
1821 | |
1822 | fn possible_values() -> impl Iterator<Item = crate::builder::PossibleValue> { |
1823 | crate::util::TRUE_LITERALS |
1824 | .iter() |
1825 | .chain(crate::util::FALSE_LITERALS.iter()) |
1826 | .copied() |
1827 | .map(|l| crate::builder::PossibleValue::new(l).hide(l != "true" && l != "false" )) |
1828 | } |
1829 | } |
1830 | |
1831 | impl TypedValueParser for FalseyValueParser { |
1832 | type Value = bool; |
1833 | |
1834 | fn parse_ref( |
1835 | &self, |
1836 | cmd: &crate::Command, |
1837 | _arg: Option<&crate::Arg>, |
1838 | value: &std::ffi::OsStr, |
1839 | ) -> Result<Self::Value, crate::Error> { |
1840 | let value = ok!(value.to_str().ok_or_else(|| { |
1841 | crate::Error::invalid_utf8( |
1842 | cmd, |
1843 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1844 | ) |
1845 | })); |
1846 | let value = if value.is_empty() { |
1847 | false |
1848 | } else { |
1849 | crate::util::str_to_bool(value).unwrap_or(true) |
1850 | }; |
1851 | Ok(value) |
1852 | } |
1853 | |
1854 | fn possible_values( |
1855 | &self, |
1856 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1857 | Some(Box::new(Self::possible_values())) |
1858 | } |
1859 | } |
1860 | |
1861 | impl Default for FalseyValueParser { |
1862 | fn default() -> Self { |
1863 | Self::new() |
1864 | } |
1865 | } |
1866 | |
1867 | /// Parse bool-like string values, everything else is `true` |
1868 | /// |
1869 | /// See also: |
1870 | /// - [`ValueParser::bool`] for different human readable bool representations |
1871 | /// - [`FalseyValueParser`] for assuming non-false is true |
1872 | /// |
1873 | /// # Example |
1874 | /// |
1875 | /// Usage: |
1876 | /// ```rust |
1877 | /// # use clap_builder as clap; |
1878 | /// let mut cmd = clap::Command::new("raw" ) |
1879 | /// .arg( |
1880 | /// clap::Arg::new("append" ) |
1881 | /// .value_parser(clap::builder::BoolishValueParser::new()) |
1882 | /// .required(true) |
1883 | /// ); |
1884 | /// |
1885 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "true" ]).unwrap(); |
1886 | /// let port: bool = *m.get_one("append" ) |
1887 | /// .expect("required" ); |
1888 | /// assert_eq!(port, true); |
1889 | /// ``` |
1890 | /// |
1891 | /// Semantics: |
1892 | /// ```rust |
1893 | /// # use clap_builder as clap; |
1894 | /// # use std::ffi::OsStr; |
1895 | /// # use clap::builder::TypedValueParser; |
1896 | /// # let cmd = clap::Command::new("test" ); |
1897 | /// # let arg = None; |
1898 | /// let value_parser = clap::builder::BoolishValueParser::new(); |
1899 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1900 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1901 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("100" )).is_err()); |
1902 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("true" )).unwrap(), true); |
1903 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("Yes" )).unwrap(), true); |
1904 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oN" )).unwrap(), true); |
1905 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("1" )).unwrap(), true); |
1906 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("false" )).unwrap(), false); |
1907 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("No" )).unwrap(), false); |
1908 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oFF" )).unwrap(), false); |
1909 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0" )).unwrap(), false); |
1910 | /// ``` |
1911 | #[derive(Copy, Clone, Debug)] |
1912 | #[non_exhaustive ] |
1913 | pub struct BoolishValueParser {} |
1914 | |
1915 | impl BoolishValueParser { |
1916 | /// Parse bool-like string values, everything else is `true` |
1917 | pub fn new() -> Self { |
1918 | Self {} |
1919 | } |
1920 | |
1921 | fn possible_values() -> impl Iterator<Item = crate::builder::PossibleValue> { |
1922 | crate::util::TRUE_LITERALS |
1923 | .iter() |
1924 | .chain(crate::util::FALSE_LITERALS.iter()) |
1925 | .copied() |
1926 | .map(|l| crate::builder::PossibleValue::new(l).hide(l != "true" && l != "false" )) |
1927 | } |
1928 | } |
1929 | |
1930 | impl TypedValueParser for BoolishValueParser { |
1931 | type Value = bool; |
1932 | |
1933 | fn parse_ref( |
1934 | &self, |
1935 | cmd: &crate::Command, |
1936 | arg: Option<&crate::Arg>, |
1937 | value: &std::ffi::OsStr, |
1938 | ) -> Result<Self::Value, crate::Error> { |
1939 | let value = ok!(value.to_str().ok_or_else(|| { |
1940 | crate::Error::invalid_utf8( |
1941 | cmd, |
1942 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1943 | ) |
1944 | })); |
1945 | let value = ok!(crate::util::str_to_bool(value).ok_or_else(|| { |
1946 | let arg = arg |
1947 | .map(|a| a.to_string()) |
1948 | .unwrap_or_else(|| "..." .to_owned()); |
1949 | crate::Error::value_validation(arg, value.to_owned(), "value was not a boolean" .into()) |
1950 | .with_cmd(cmd) |
1951 | })); |
1952 | Ok(value) |
1953 | } |
1954 | |
1955 | fn possible_values( |
1956 | &self, |
1957 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1958 | Some(Box::new(Self::possible_values())) |
1959 | } |
1960 | } |
1961 | |
1962 | impl Default for BoolishValueParser { |
1963 | fn default() -> Self { |
1964 | Self::new() |
1965 | } |
1966 | } |
1967 | |
1968 | /// Parse non-empty string values |
1969 | /// |
1970 | /// See also: |
1971 | /// - [`ValueParser::string`] |
1972 | /// |
1973 | /// # Example |
1974 | /// |
1975 | /// Usage: |
1976 | /// ```rust |
1977 | /// # use clap_builder as clap; |
1978 | /// let mut cmd = clap::Command::new("raw" ) |
1979 | /// .arg( |
1980 | /// clap::Arg::new("append" ) |
1981 | /// .value_parser(clap::builder::NonEmptyStringValueParser::new()) |
1982 | /// .required(true) |
1983 | /// ); |
1984 | /// |
1985 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "true" ]).unwrap(); |
1986 | /// let port: &String = m.get_one("append" ) |
1987 | /// .expect("required" ); |
1988 | /// assert_eq!(port, "true" ); |
1989 | /// ``` |
1990 | /// |
1991 | /// Semantics: |
1992 | /// ```rust |
1993 | /// # use clap_builder as clap; |
1994 | /// # use std::ffi::OsStr; |
1995 | /// # use clap::builder::TypedValueParser; |
1996 | /// # let cmd = clap::Command::new("test" ); |
1997 | /// # let arg = None; |
1998 | /// let value_parser = clap::builder::NonEmptyStringValueParser::new(); |
1999 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).unwrap(), "random" ); |
2000 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
2001 | /// ``` |
2002 | #[derive(Copy, Clone, Debug)] |
2003 | #[non_exhaustive ] |
2004 | pub struct NonEmptyStringValueParser {} |
2005 | |
2006 | impl NonEmptyStringValueParser { |
2007 | /// Parse non-empty string values |
2008 | pub fn new() -> Self { |
2009 | Self {} |
2010 | } |
2011 | } |
2012 | |
2013 | impl TypedValueParser for NonEmptyStringValueParser { |
2014 | type Value = String; |
2015 | |
2016 | fn parse_ref( |
2017 | &self, |
2018 | cmd: &crate::Command, |
2019 | arg: Option<&crate::Arg>, |
2020 | value: &std::ffi::OsStr, |
2021 | ) -> Result<Self::Value, crate::Error> { |
2022 | if value.is_empty() { |
2023 | return Err(crate::Error::empty_value( |
2024 | cmd, |
2025 | &[], |
2026 | arg.map(ToString::to_string) |
2027 | .unwrap_or_else(|| "..." .to_owned()), |
2028 | )); |
2029 | } |
2030 | let value = ok!(value.to_str().ok_or_else(|| { |
2031 | crate::Error::invalid_utf8( |
2032 | cmd, |
2033 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
2034 | ) |
2035 | })); |
2036 | Ok(value.to_owned()) |
2037 | } |
2038 | } |
2039 | |
2040 | impl Default for NonEmptyStringValueParser { |
2041 | fn default() -> Self { |
2042 | Self::new() |
2043 | } |
2044 | } |
2045 | |
2046 | /// Adapt a `TypedValueParser` from one value to another |
2047 | /// |
2048 | /// See [`TypedValueParser::map`] |
2049 | #[derive(Clone, Debug)] |
2050 | pub struct MapValueParser<P, F> { |
2051 | parser: P, |
2052 | func: F, |
2053 | } |
2054 | |
2055 | impl<P, F, T> MapValueParser<P, F> |
2056 | where |
2057 | P: TypedValueParser, |
2058 | P::Value: Send + Sync + Clone, |
2059 | F: Fn(P::Value) -> T + Clone, |
2060 | T: Send + Sync + Clone, |
2061 | { |
2062 | fn new(parser: P, func: F) -> Self { |
2063 | Self { parser, func } |
2064 | } |
2065 | } |
2066 | |
2067 | impl<P, F, T> TypedValueParser for MapValueParser<P, F> |
2068 | where |
2069 | P: TypedValueParser, |
2070 | P::Value: Send + Sync + Clone, |
2071 | F: Fn(P::Value) -> T + Clone + Send + Sync + 'static, |
2072 | T: Send + Sync + Clone, |
2073 | { |
2074 | type Value = T; |
2075 | |
2076 | fn parse_ref( |
2077 | &self, |
2078 | cmd: &crate::Command, |
2079 | arg: Option<&crate::Arg>, |
2080 | value: &std::ffi::OsStr, |
2081 | ) -> Result<Self::Value, crate::Error> { |
2082 | let value = ok!(self.parser.parse_ref(cmd, arg, value)); |
2083 | let value = (self.func)(value); |
2084 | Ok(value) |
2085 | } |
2086 | |
2087 | fn parse( |
2088 | &self, |
2089 | cmd: &crate::Command, |
2090 | arg: Option<&crate::Arg>, |
2091 | value: std::ffi::OsString, |
2092 | ) -> Result<Self::Value, crate::Error> { |
2093 | let value = ok!(self.parser.parse(cmd, arg, value)); |
2094 | let value = (self.func)(value); |
2095 | Ok(value) |
2096 | } |
2097 | |
2098 | fn possible_values( |
2099 | &self, |
2100 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
2101 | self.parser.possible_values() |
2102 | } |
2103 | } |
2104 | |
2105 | /// Adapt a `TypedValueParser` from one value to another |
2106 | /// |
2107 | /// See [`TypedValueParser::try_map`] |
2108 | #[derive(Clone, Debug)] |
2109 | pub struct TryMapValueParser<P, F> { |
2110 | parser: P, |
2111 | func: F, |
2112 | } |
2113 | |
2114 | impl<P, F, T, E> TryMapValueParser<P, F> |
2115 | where |
2116 | P: TypedValueParser, |
2117 | P::Value: Send + Sync + Clone, |
2118 | F: Fn(P::Value) -> Result<T, E> + Clone + Send + Sync + 'static, |
2119 | T: Send + Sync + Clone, |
2120 | E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
2121 | { |
2122 | fn new(parser: P, func: F) -> Self { |
2123 | Self { parser, func } |
2124 | } |
2125 | } |
2126 | |
2127 | impl<P, F, T, E> TypedValueParser for TryMapValueParser<P, F> |
2128 | where |
2129 | P: TypedValueParser, |
2130 | P::Value: Send + Sync + Clone, |
2131 | F: Fn(P::Value) -> Result<T, E> + Clone + Send + Sync + 'static, |
2132 | T: Send + Sync + Clone, |
2133 | E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
2134 | { |
2135 | type Value = T; |
2136 | |
2137 | fn parse_ref( |
2138 | &self, |
2139 | cmd: &crate::Command, |
2140 | arg: Option<&crate::Arg>, |
2141 | value: &std::ffi::OsStr, |
2142 | ) -> Result<Self::Value, crate::Error> { |
2143 | let mid_value = ok!(self.parser.parse_ref(cmd, arg, value)); |
2144 | let value = ok!((self.func)(mid_value).map_err(|e| { |
2145 | let arg = arg |
2146 | .map(|a| a.to_string()) |
2147 | .unwrap_or_else(|| "..." .to_owned()); |
2148 | crate::Error::value_validation(arg, value.to_string_lossy().into_owned(), e.into()) |
2149 | .with_cmd(cmd) |
2150 | })); |
2151 | Ok(value) |
2152 | } |
2153 | |
2154 | fn possible_values( |
2155 | &self, |
2156 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
2157 | self.parser.possible_values() |
2158 | } |
2159 | } |
2160 | |
2161 | /// When encountered, report [ErrorKind::UnknownArgument][crate::error::ErrorKind::UnknownArgument] |
2162 | /// |
2163 | /// Useful to help users migrate, either from old versions or similar tools. |
2164 | /// |
2165 | /// # Examples |
2166 | /// |
2167 | /// ```rust |
2168 | /// # use clap_builder as clap; |
2169 | /// # use clap::Command; |
2170 | /// # use clap::Arg; |
2171 | /// let cmd = Command::new("mycmd" ) |
2172 | /// .args([ |
2173 | /// Arg::new("current-dir" ) |
2174 | /// .short('C' ), |
2175 | /// Arg::new("current-dir-unknown" ) |
2176 | /// .long("cwd" ) |
2177 | /// .aliases(["current-dir" , "directory" , "working-directory" , "root" ]) |
2178 | /// .value_parser(clap::builder::UnknownArgumentValueParser::suggest_arg("-C" )) |
2179 | /// .hide(true), |
2180 | /// ]); |
2181 | /// |
2182 | /// // Use a supported version of the argument |
2183 | /// let matches = cmd.clone().try_get_matches_from(["mycmd" , "-C" , ".." ]).unwrap(); |
2184 | /// assert!(matches.contains_id("current-dir" )); |
2185 | /// assert_eq!( |
2186 | /// matches.get_many::<String>("current-dir" ).unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(), |
2187 | /// vec![".." ] |
2188 | /// ); |
2189 | /// |
2190 | /// // Use one of the invalid versions |
2191 | /// let err = cmd.try_get_matches_from(["mycmd" , "--cwd" , ".." ]).unwrap_err(); |
2192 | /// assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument); |
2193 | /// ``` |
2194 | #[derive(Clone, Debug)] |
2195 | pub struct UnknownArgumentValueParser { |
2196 | arg: Option<Str>, |
2197 | suggestions: Vec<StyledStr>, |
2198 | } |
2199 | |
2200 | impl UnknownArgumentValueParser { |
2201 | /// Suggest an alternative argument |
2202 | pub fn suggest_arg(arg: impl Into<Str>) -> Self { |
2203 | Self { |
2204 | arg: Some(arg.into()), |
2205 | suggestions: Default::default(), |
2206 | } |
2207 | } |
2208 | |
2209 | /// Provide a general suggestion |
2210 | pub fn suggest(text: impl Into<StyledStr>) -> Self { |
2211 | Self { |
2212 | arg: Default::default(), |
2213 | suggestions: vec![text.into()], |
2214 | } |
2215 | } |
2216 | |
2217 | /// Extend the suggestions |
2218 | pub fn and_suggest(mut self, text: impl Into<StyledStr>) -> Self { |
2219 | self.suggestions.push(text.into()); |
2220 | self |
2221 | } |
2222 | } |
2223 | |
2224 | impl TypedValueParser for UnknownArgumentValueParser { |
2225 | type Value = String; |
2226 | |
2227 | fn parse_ref( |
2228 | &self, |
2229 | cmd: &crate::Command, |
2230 | arg: Option<&crate::Arg>, |
2231 | value: &std::ffi::OsStr, |
2232 | ) -> Result<Self::Value, crate::Error> { |
2233 | TypedValueParser::parse_ref_(self, cmd, arg, value, ValueSource::CommandLine) |
2234 | } |
2235 | |
2236 | fn parse_ref_( |
2237 | &self, |
2238 | cmd: &crate::Command, |
2239 | arg: Option<&crate::Arg>, |
2240 | _value: &std::ffi::OsStr, |
2241 | source: ValueSource, |
2242 | ) -> Result<Self::Value, crate::Error> { |
2243 | match source { |
2244 | ValueSource::DefaultValue => { |
2245 | TypedValueParser::parse_ref_(&StringValueParser::new(), cmd, arg, _value, source) |
2246 | } |
2247 | ValueSource::EnvVariable | ValueSource::CommandLine => { |
2248 | let arg = match arg { |
2249 | Some(arg) => arg.to_string(), |
2250 | None => ".." .to_owned(), |
2251 | }; |
2252 | let err = crate::Error::unknown_argument( |
2253 | cmd, |
2254 | arg, |
2255 | self.arg.as_ref().map(|s| (s.as_str().to_owned(), None)), |
2256 | false, |
2257 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
2258 | ); |
2259 | #[cfg (feature = "error-context" )] |
2260 | let err = { |
2261 | debug_assert_eq!( |
2262 | err.get(crate::error::ContextKind::Suggested), |
2263 | None, |
2264 | "Assuming `Error::unknown_argument` doesn't apply any `Suggested` so we can without caution" |
2265 | ); |
2266 | err.insert_context_unchecked( |
2267 | crate::error::ContextKind::Suggested, |
2268 | crate::error::ContextValue::StyledStrs(self.suggestions.clone()), |
2269 | ) |
2270 | }; |
2271 | Err(err) |
2272 | } |
2273 | } |
2274 | } |
2275 | } |
2276 | |
2277 | /// Register a type with [value_parser!][crate::value_parser!] |
2278 | /// |
2279 | /// # Example |
2280 | /// |
2281 | /// ```rust |
2282 | /// # use clap_builder as clap; |
2283 | /// #[derive(Copy, Clone, Debug)] |
2284 | /// pub struct Custom(u32); |
2285 | /// |
2286 | /// impl clap::builder::ValueParserFactory for Custom { |
2287 | /// type Parser = CustomValueParser; |
2288 | /// fn value_parser() -> Self::Parser { |
2289 | /// CustomValueParser |
2290 | /// } |
2291 | /// } |
2292 | /// |
2293 | /// #[derive(Clone, Debug)] |
2294 | /// pub struct CustomValueParser; |
2295 | /// impl clap::builder::TypedValueParser for CustomValueParser { |
2296 | /// type Value = Custom; |
2297 | /// |
2298 | /// fn parse_ref( |
2299 | /// &self, |
2300 | /// cmd: &clap::Command, |
2301 | /// arg: Option<&clap::Arg>, |
2302 | /// value: &std::ffi::OsStr, |
2303 | /// ) -> Result<Self::Value, clap::Error> { |
2304 | /// let inner = clap::value_parser!(u32); |
2305 | /// let val = inner.parse_ref(cmd, arg, value)?; |
2306 | /// Ok(Custom(val)) |
2307 | /// } |
2308 | /// } |
2309 | /// |
2310 | /// let parser: CustomValueParser = clap::value_parser!(Custom); |
2311 | /// ``` |
2312 | pub trait ValueParserFactory { |
2313 | /// Generated parser, usually [`ValueParser`]. |
2314 | /// |
2315 | /// It should at least be a type that supports `Into<ValueParser>`. A non-`ValueParser` type |
2316 | /// allows the caller to do further initialization on the parser. |
2317 | type Parser; |
2318 | |
2319 | /// Create the specified [`Self::Parser`] |
2320 | fn value_parser() -> Self::Parser; |
2321 | } |
2322 | impl ValueParserFactory for String { |
2323 | type Parser = ValueParser; |
2324 | fn value_parser() -> Self::Parser { |
2325 | ValueParser::string() // Default `clap_derive` to optimized implementation |
2326 | } |
2327 | } |
2328 | impl ValueParserFactory for Box<str> { |
2329 | type Parser = MapValueParser<StringValueParser, fn(String) -> Box<str>>; |
2330 | fn value_parser() -> Self::Parser { |
2331 | StringValueParser::new().map(String::into_boxed_str) |
2332 | } |
2333 | } |
2334 | impl ValueParserFactory for std::ffi::OsString { |
2335 | type Parser = ValueParser; |
2336 | fn value_parser() -> Self::Parser { |
2337 | ValueParser::os_string() // Default `clap_derive` to optimized implementation |
2338 | } |
2339 | } |
2340 | impl ValueParserFactory for Box<std::ffi::OsStr> { |
2341 | type Parser = |
2342 | MapValueParser<OsStringValueParser, fn(std::ffi::OsString) -> Box<std::ffi::OsStr>>; |
2343 | fn value_parser() -> Self::Parser { |
2344 | OsStringValueParser::new().map(std::ffi::OsString::into_boxed_os_str) |
2345 | } |
2346 | } |
2347 | impl ValueParserFactory for std::path::PathBuf { |
2348 | type Parser = ValueParser; |
2349 | fn value_parser() -> Self::Parser { |
2350 | ValueParser::path_buf() // Default `clap_derive` to optimized implementation |
2351 | } |
2352 | } |
2353 | impl ValueParserFactory for Box<std::path::Path> { |
2354 | type Parser = |
2355 | MapValueParser<PathBufValueParser, fn(std::path::PathBuf) -> Box<std::path::Path>>; |
2356 | fn value_parser() -> Self::Parser { |
2357 | PathBufValueParser::new().map(std::path::PathBuf::into_boxed_path) |
2358 | } |
2359 | } |
2360 | impl ValueParserFactory for bool { |
2361 | type Parser = ValueParser; |
2362 | fn value_parser() -> Self::Parser { |
2363 | ValueParser::bool() // Default `clap_derive` to optimized implementation |
2364 | } |
2365 | } |
2366 | impl ValueParserFactory for u8 { |
2367 | type Parser = RangedI64ValueParser<u8>; |
2368 | fn value_parser() -> Self::Parser { |
2369 | let start: i64 = u8::MIN.into(); |
2370 | let end: i64 = u8::MAX.into(); |
2371 | RangedI64ValueParser::new().range(start..=end) |
2372 | } |
2373 | } |
2374 | impl ValueParserFactory for i8 { |
2375 | type Parser = RangedI64ValueParser<i8>; |
2376 | fn value_parser() -> Self::Parser { |
2377 | let start: i64 = i8::MIN.into(); |
2378 | let end: i64 = i8::MAX.into(); |
2379 | RangedI64ValueParser::new().range(start..=end) |
2380 | } |
2381 | } |
2382 | impl ValueParserFactory for u16 { |
2383 | type Parser = RangedI64ValueParser<u16>; |
2384 | fn value_parser() -> Self::Parser { |
2385 | let start: i64 = u16::MIN.into(); |
2386 | let end: i64 = u16::MAX.into(); |
2387 | RangedI64ValueParser::new().range(start..=end) |
2388 | } |
2389 | } |
2390 | impl ValueParserFactory for i16 { |
2391 | type Parser = RangedI64ValueParser<i16>; |
2392 | fn value_parser() -> Self::Parser { |
2393 | let start: i64 = i16::MIN.into(); |
2394 | let end: i64 = i16::MAX.into(); |
2395 | RangedI64ValueParser::new().range(start..=end) |
2396 | } |
2397 | } |
2398 | impl ValueParserFactory for u32 { |
2399 | type Parser = RangedI64ValueParser<u32>; |
2400 | fn value_parser() -> Self::Parser { |
2401 | let start: i64 = u32::MIN.into(); |
2402 | let end: i64 = u32::MAX.into(); |
2403 | RangedI64ValueParser::new().range(start..=end) |
2404 | } |
2405 | } |
2406 | impl ValueParserFactory for i32 { |
2407 | type Parser = RangedI64ValueParser<i32>; |
2408 | fn value_parser() -> Self::Parser { |
2409 | let start: i64 = i32::MIN.into(); |
2410 | let end: i64 = i32::MAX.into(); |
2411 | RangedI64ValueParser::new().range(start..=end) |
2412 | } |
2413 | } |
2414 | impl ValueParserFactory for u64 { |
2415 | type Parser = RangedU64ValueParser<u64>; |
2416 | fn value_parser() -> Self::Parser { |
2417 | RangedU64ValueParser::new() |
2418 | } |
2419 | } |
2420 | impl ValueParserFactory for i64 { |
2421 | type Parser = RangedI64ValueParser<i64>; |
2422 | fn value_parser() -> Self::Parser { |
2423 | RangedI64ValueParser::new() |
2424 | } |
2425 | } |
2426 | impl<T> ValueParserFactory for std::num::Wrapping<T> |
2427 | where |
2428 | T: ValueParserFactory, |
2429 | <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, |
2430 | T: Send + Sync + Clone, |
2431 | { |
2432 | type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> std::num::Wrapping<T>>; |
2433 | fn value_parser() -> Self::Parser { |
2434 | T::value_parser().map(std::num::Wrapping) |
2435 | } |
2436 | } |
2437 | impl<T> ValueParserFactory for Box<T> |
2438 | where |
2439 | T: ValueParserFactory, |
2440 | <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, |
2441 | T: Send + Sync + Clone, |
2442 | { |
2443 | type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> Box<T>>; |
2444 | fn value_parser() -> Self::Parser { |
2445 | T::value_parser().map(Box::new) |
2446 | } |
2447 | } |
2448 | impl<T> ValueParserFactory for std::sync::Arc<T> |
2449 | where |
2450 | T: ValueParserFactory, |
2451 | <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, |
2452 | T: Send + Sync + Clone, |
2453 | { |
2454 | type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> std::sync::Arc<T>>; |
2455 | fn value_parser() -> Self::Parser { |
2456 | T::value_parser().map(std::sync::Arc::new) |
2457 | } |
2458 | } |
2459 | |
2460 | #[doc (hidden)] |
2461 | #[derive(Debug)] |
2462 | pub struct _AutoValueParser<T>(std::marker::PhantomData<T>); |
2463 | |
2464 | impl<T> _AutoValueParser<T> { |
2465 | #[doc (hidden)] |
2466 | #[allow (clippy::new_without_default)] |
2467 | pub fn new() -> Self { |
2468 | Self(Default::default()) |
2469 | } |
2470 | } |
2471 | |
2472 | /// Unstable [`ValueParser`] |
2473 | /// |
2474 | /// Implementation may change to more specific instance in the future |
2475 | #[doc (hidden)] |
2476 | #[derive(Debug)] |
2477 | pub struct _AnonymousValueParser(ValueParser); |
2478 | |
2479 | #[doc (hidden)] |
2480 | pub mod via_prelude { |
2481 | use super::*; |
2482 | |
2483 | #[doc (hidden)] |
2484 | pub trait _ValueParserViaFactory: private::_ValueParserViaFactorySealed { |
2485 | type Parser; |
2486 | fn value_parser(&self) -> Self::Parser; |
2487 | } |
2488 | impl<P: ValueParserFactory> _ValueParserViaFactory for &&&&&&_AutoValueParser<P> { |
2489 | type Parser = P::Parser; |
2490 | fn value_parser(&self) -> Self::Parser { |
2491 | P::value_parser() |
2492 | } |
2493 | } |
2494 | |
2495 | #[doc (hidden)] |
2496 | pub trait _ValueParserViaValueEnum: private::_ValueParserViaValueEnumSealed { |
2497 | type Output; |
2498 | |
2499 | fn value_parser(&self) -> Self::Output; |
2500 | } |
2501 | impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> _ValueParserViaValueEnum |
2502 | for &&&&&_AutoValueParser<E> |
2503 | { |
2504 | type Output = EnumValueParser<E>; |
2505 | |
2506 | fn value_parser(&self) -> Self::Output { |
2507 | EnumValueParser::<E>::new() |
2508 | } |
2509 | } |
2510 | |
2511 | #[doc (hidden)] |
2512 | pub trait _ValueParserViaFromOsString: private::_ValueParserViaFromOsStringSealed { |
2513 | fn value_parser(&self) -> _AnonymousValueParser; |
2514 | } |
2515 | impl<FromOsString> _ValueParserViaFromOsString for &&&&_AutoValueParser<FromOsString> |
2516 | where |
2517 | FromOsString: From<std::ffi::OsString> + std::any::Any + Clone + Send + Sync + 'static, |
2518 | { |
2519 | fn value_parser(&self) -> _AnonymousValueParser { |
2520 | _AnonymousValueParser( |
2521 | OsStringValueParser::new() |
2522 | .map(|s| FromOsString::from(s)) |
2523 | .into(), |
2524 | ) |
2525 | } |
2526 | } |
2527 | |
2528 | #[doc (hidden)] |
2529 | pub trait _ValueParserViaFromOsStr: private::_ValueParserViaFromOsStrSealed { |
2530 | fn value_parser(&self) -> _AnonymousValueParser; |
2531 | } |
2532 | impl<FromOsStr> _ValueParserViaFromOsStr for &&&_AutoValueParser<FromOsStr> |
2533 | where |
2534 | FromOsStr: |
2535 | for<'s> From<&'s std::ffi::OsStr> + std::any::Any + Clone + Send + Sync + 'static, |
2536 | { |
2537 | fn value_parser(&self) -> _AnonymousValueParser { |
2538 | _AnonymousValueParser( |
2539 | OsStringValueParser::new() |
2540 | .map(|s| FromOsStr::from(&s)) |
2541 | .into(), |
2542 | ) |
2543 | } |
2544 | } |
2545 | |
2546 | #[doc (hidden)] |
2547 | pub trait _ValueParserViaFromString: private::_ValueParserViaFromStringSealed { |
2548 | fn value_parser(&self) -> _AnonymousValueParser; |
2549 | } |
2550 | impl<FromString> _ValueParserViaFromString for &&_AutoValueParser<FromString> |
2551 | where |
2552 | FromString: From<String> + std::any::Any + Clone + Send + Sync + 'static, |
2553 | { |
2554 | fn value_parser(&self) -> _AnonymousValueParser { |
2555 | _AnonymousValueParser(StringValueParser::new().map(|s| FromString::from(s)).into()) |
2556 | } |
2557 | } |
2558 | |
2559 | #[doc (hidden)] |
2560 | pub trait _ValueParserViaFromStr: private::_ValueParserViaFromStrSealed { |
2561 | fn value_parser(&self) -> _AnonymousValueParser; |
2562 | } |
2563 | impl<FromStr> _ValueParserViaFromStr for &_AutoValueParser<FromStr> |
2564 | where |
2565 | FromStr: for<'s> From<&'s str> + std::any::Any + Clone + Send + Sync + 'static, |
2566 | { |
2567 | fn value_parser(&self) -> _AnonymousValueParser { |
2568 | _AnonymousValueParser(StringValueParser::new().map(|s| FromStr::from(&s)).into()) |
2569 | } |
2570 | } |
2571 | |
2572 | #[doc (hidden)] |
2573 | pub trait _ValueParserViaParse: private::_ValueParserViaParseSealed { |
2574 | fn value_parser(&self) -> _AnonymousValueParser; |
2575 | } |
2576 | impl<Parse> _ValueParserViaParse for _AutoValueParser<Parse> |
2577 | where |
2578 | Parse: std::str::FromStr + std::any::Any + Clone + Send + Sync + 'static, |
2579 | <Parse as std::str::FromStr>::Err: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
2580 | { |
2581 | fn value_parser(&self) -> _AnonymousValueParser { |
2582 | let func: fn(&str) -> Result<Parse, <Parse as std::str::FromStr>::Err> = |
2583 | Parse::from_str; |
2584 | _AnonymousValueParser(ValueParser::new(func)) |
2585 | } |
2586 | } |
2587 | } |
2588 | |
2589 | /// Select a [`ValueParser`] implementation from the intended type |
2590 | /// |
2591 | /// Supported types |
2592 | /// - [`ValueParserFactory` types][ValueParserFactory], including |
2593 | /// - [Native types][ValueParser]: `bool`, `String`, `OsString`, `PathBuf` |
2594 | /// - [Ranged numeric types][RangedI64ValueParser]: `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64` |
2595 | /// - [`ValueEnum` types][crate::ValueEnum] |
2596 | /// - [`From<OsString>` types][std::convert::From] and [`From<&OsStr>` types][std::convert::From] |
2597 | /// - [`From<String>` types][std::convert::From] and [`From<&str>` types][std::convert::From] |
2598 | /// - [`FromStr` types][std::str::FromStr], including usize, isize |
2599 | /// |
2600 | /// # Example |
2601 | /// |
2602 | /// Usage: |
2603 | /// ```rust |
2604 | /// # use clap_builder as clap; |
2605 | /// # use std::path::PathBuf; |
2606 | /// # use std::path::Path; |
2607 | /// let mut cmd = clap::Command::new("raw" ) |
2608 | /// .arg( |
2609 | /// clap::Arg::new("output" ) |
2610 | /// .value_parser(clap::value_parser!(PathBuf)) |
2611 | /// .required(true) |
2612 | /// ); |
2613 | /// |
2614 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "file.txt" ]).unwrap(); |
2615 | /// let port: &PathBuf = m.get_one("output" ) |
2616 | /// .expect("required" ); |
2617 | /// assert_eq!(port, Path::new("file.txt" )); |
2618 | /// ``` |
2619 | /// |
2620 | /// Example mappings: |
2621 | /// ```rust |
2622 | /// # use clap_builder as clap; |
2623 | /// # use clap::ColorChoice; |
2624 | /// // Built-in types |
2625 | /// let parser = clap::value_parser!(String); |
2626 | /// assert_eq!(format!("{parser:?}" ), "ValueParser::string" ); |
2627 | /// let parser = clap::value_parser!(std::ffi::OsString); |
2628 | /// assert_eq!(format!("{parser:?}" ), "ValueParser::os_string" ); |
2629 | /// let parser = clap::value_parser!(std::path::PathBuf); |
2630 | /// assert_eq!(format!("{parser:?}" ), "ValueParser::path_buf" ); |
2631 | /// clap::value_parser!(u16).range(3000..); |
2632 | /// clap::value_parser!(u64).range(3000..); |
2633 | /// |
2634 | /// // FromStr types |
2635 | /// let parser = clap::value_parser!(usize); |
2636 | /// assert_eq!(format!("{parser:?}" ), "_AnonymousValueParser(ValueParser::other(usize))" ); |
2637 | /// |
2638 | /// // ValueEnum types |
2639 | /// clap::value_parser!(ColorChoice); |
2640 | /// ``` |
2641 | #[macro_export ] |
2642 | macro_rules! value_parser { |
2643 | ($name:ty) => {{ |
2644 | use $crate::builder::via_prelude::*; |
2645 | let auto = $crate::builder::_AutoValueParser::<$name>::new(); |
2646 | (&&&&&&auto).value_parser() |
2647 | }}; |
2648 | } |
2649 | |
2650 | mod private { |
2651 | use super::*; |
2652 | |
2653 | // Prefer these so `clap_derive` defaults to optimized implementations |
2654 | pub trait _ValueParserViaSelfSealed {} |
2655 | impl<P: Into<ValueParser>> _ValueParserViaSelfSealed for &&&&&&&_AutoValueParser<P> {} |
2656 | |
2657 | pub trait _ValueParserViaFactorySealed {} |
2658 | impl<P: ValueParserFactory> _ValueParserViaFactorySealed for &&&&&&_AutoValueParser<P> {} |
2659 | |
2660 | pub trait _ValueParserViaValueEnumSealed {} |
2661 | impl<E: crate::ValueEnum> _ValueParserViaValueEnumSealed for &&&&&_AutoValueParser<E> {} |
2662 | |
2663 | pub trait _ValueParserViaFromOsStringSealed {} |
2664 | impl<FromOsString> _ValueParserViaFromOsStringSealed for &&&&_AutoValueParser<FromOsString> where |
2665 | FromOsString: From<std::ffi::OsString> + std::any::Any + Send + Sync + 'static |
2666 | { |
2667 | } |
2668 | |
2669 | pub trait _ValueParserViaFromOsStrSealed {} |
2670 | impl<FromOsStr> _ValueParserViaFromOsStrSealed for &&&_AutoValueParser<FromOsStr> where |
2671 | FromOsStr: for<'s> From<&'s std::ffi::OsStr> + std::any::Any + Send + Sync + 'static |
2672 | { |
2673 | } |
2674 | |
2675 | pub trait _ValueParserViaFromStringSealed {} |
2676 | impl<FromString> _ValueParserViaFromStringSealed for &&_AutoValueParser<FromString> where |
2677 | FromString: From<String> + std::any::Any + Send + Sync + 'static |
2678 | { |
2679 | } |
2680 | |
2681 | pub trait _ValueParserViaFromStrSealed {} |
2682 | impl<FromStr> _ValueParserViaFromStrSealed for &_AutoValueParser<FromStr> where |
2683 | FromStr: for<'s> From<&'s str> + std::any::Any + Send + Sync + 'static |
2684 | { |
2685 | } |
2686 | |
2687 | pub trait _ValueParserViaParseSealed {} |
2688 | impl<Parse> _ValueParserViaParseSealed for _AutoValueParser<Parse> |
2689 | where |
2690 | Parse: std::str::FromStr + std::any::Any + Send + Sync + 'static, |
2691 | <Parse as std::str::FromStr>::Err: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
2692 | { |
2693 | } |
2694 | } |
2695 | |
2696 | #[cfg (test)] |
2697 | mod test { |
2698 | use super::*; |
2699 | |
2700 | #[test] |
2701 | fn ensure_typed_applies_to_parse() { |
2702 | fn parse(_: &str) -> Result<usize, std::io::Error> { |
2703 | Ok(10) |
2704 | } |
2705 | let cmd = crate::Command::new("cmd" ); |
2706 | let arg = None; |
2707 | assert_eq!( |
2708 | TypedValueParser::parse_ref(&parse, &cmd, arg, std::ffi::OsStr::new("foo" )).unwrap(), |
2709 | 10 |
2710 | ); |
2711 | } |
2712 | } |
2713 | |