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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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(name:"ValueParser::bool" ).finish(), |
570 | ValueParserInner::String => f.debug_struct(name:"ValueParser::string" ).finish(), |
571 | ValueParserInner::OsString => f.debug_struct(name:"ValueParser::os_string" ).finish(), |
572 | ValueParserInner::PathBuf => f.debug_struct(name:"ValueParser::path_buf" ).finish(), |
573 | ValueParserInner::Other(o: &Box) => 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: &Box) => 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 | /// Describes the content of `AnyValue` |
610 | fn type_id(&self) -> AnyValueId; |
611 | |
612 | fn possible_values( |
613 | &self, |
614 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>>; |
615 | |
616 | fn clone_any(&self) -> Box<dyn AnyValueParser>; |
617 | } |
618 | |
619 | impl<T, P> AnyValueParser for P |
620 | where |
621 | T: std::any::Any + Clone + Send + Sync + 'static, |
622 | P: TypedValueParser<Value = T>, |
623 | { |
624 | fn parse_ref( |
625 | &self, |
626 | cmd: &crate::Command, |
627 | arg: Option<&crate::Arg>, |
628 | value: &std::ffi::OsStr, |
629 | ) -> Result<AnyValue, crate::Error> { |
630 | let value = ok!(TypedValueParser::parse_ref(self, cmd, arg, value)); |
631 | Ok(AnyValue::new(value)) |
632 | } |
633 | |
634 | fn parse_ref_( |
635 | &self, |
636 | cmd: &crate::Command, |
637 | arg: Option<&crate::Arg>, |
638 | value: &std::ffi::OsStr, |
639 | source: ValueSource, |
640 | ) -> Result<AnyValue, crate::Error> { |
641 | let value = ok!(TypedValueParser::parse_ref_(self, cmd, arg, value, source)); |
642 | Ok(AnyValue::new(value)) |
643 | } |
644 | |
645 | fn type_id(&self) -> AnyValueId { |
646 | AnyValueId::of::<T>() |
647 | } |
648 | |
649 | fn possible_values( |
650 | &self, |
651 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
652 | P::possible_values(self) |
653 | } |
654 | |
655 | fn clone_any(&self) -> Box<dyn AnyValueParser> { |
656 | Box::new(self.clone()) |
657 | } |
658 | } |
659 | |
660 | /// Parse/validate argument values |
661 | /// |
662 | /// As alternatives to implementing `TypedValueParser`, |
663 | /// - Use `Fn(&str) -> Result<T, E>` which implements `TypedValueParser` |
664 | /// - [`TypedValueParser::map`] or [`TypedValueParser::try_map`] to adapt an existing `TypedValueParser` |
665 | /// |
666 | /// See `ValueParserFactory` to register `TypedValueParser::Value` with |
667 | /// [`value_parser!`][crate::value_parser]. |
668 | /// |
669 | /// # Example |
670 | /// |
671 | /// ```rust |
672 | /// # #[cfg (feature = "error-context" )] { |
673 | /// # use clap_builder as clap; |
674 | /// # use clap::error::ErrorKind; |
675 | /// # use clap::error::ContextKind; |
676 | /// # use clap::error::ContextValue; |
677 | /// #[derive(Clone)] |
678 | /// struct Custom(u32); |
679 | /// |
680 | /// #[derive(Clone)] |
681 | /// struct CustomValueParser; |
682 | /// |
683 | /// impl clap::builder::TypedValueParser for CustomValueParser { |
684 | /// type Value = Custom; |
685 | /// |
686 | /// fn parse_ref( |
687 | /// &self, |
688 | /// cmd: &clap::Command, |
689 | /// arg: Option<&clap::Arg>, |
690 | /// value: &std::ffi::OsStr, |
691 | /// ) -> Result<Self::Value, clap::Error> { |
692 | /// let inner = clap::value_parser!(u32); |
693 | /// let val = inner.parse_ref(cmd, arg, value)?; |
694 | /// |
695 | /// const INVALID_VALUE: u32 = 10; |
696 | /// if val == INVALID_VALUE { |
697 | /// let mut err = clap::Error::new(ErrorKind::ValueValidation) |
698 | /// .with_cmd(cmd); |
699 | /// if let Some(arg) = arg { |
700 | /// err.insert(ContextKind::InvalidArg, ContextValue::String(arg.to_string())); |
701 | /// } |
702 | /// err.insert(ContextKind::InvalidValue, ContextValue::String(INVALID_VALUE.to_string())); |
703 | /// return Err(err); |
704 | /// } |
705 | /// |
706 | /// Ok(Custom(val)) |
707 | /// } |
708 | /// } |
709 | /// # } |
710 | /// ``` |
711 | pub trait TypedValueParser: Clone + Send + Sync + 'static { |
712 | /// Argument's value type |
713 | type Value: Send + Sync + Clone; |
714 | |
715 | /// Parse the argument value |
716 | /// |
717 | /// When `arg` is `None`, an external subcommand value is being parsed. |
718 | fn parse_ref( |
719 | &self, |
720 | cmd: &crate::Command, |
721 | arg: Option<&crate::Arg>, |
722 | value: &std::ffi::OsStr, |
723 | ) -> Result<Self::Value, crate::Error>; |
724 | |
725 | /// Parse the argument value |
726 | /// |
727 | /// When `arg` is `None`, an external subcommand value is being parsed. |
728 | fn parse_ref_( |
729 | &self, |
730 | cmd: &crate::Command, |
731 | arg: Option<&crate::Arg>, |
732 | value: &std::ffi::OsStr, |
733 | _source: ValueSource, |
734 | ) -> Result<Self::Value, crate::Error> { |
735 | self.parse_ref(cmd, arg, value) |
736 | } |
737 | |
738 | /// Parse the argument value |
739 | /// |
740 | /// When `arg` is `None`, an external subcommand value is being parsed. |
741 | fn parse( |
742 | &self, |
743 | cmd: &crate::Command, |
744 | arg: Option<&crate::Arg>, |
745 | value: std::ffi::OsString, |
746 | ) -> Result<Self::Value, crate::Error> { |
747 | self.parse_ref(cmd, arg, &value) |
748 | } |
749 | |
750 | /// Parse the argument value |
751 | /// |
752 | /// When `arg` is `None`, an external subcommand value is being parsed. |
753 | fn parse_( |
754 | &self, |
755 | cmd: &crate::Command, |
756 | arg: Option<&crate::Arg>, |
757 | value: std::ffi::OsString, |
758 | _source: ValueSource, |
759 | ) -> Result<Self::Value, crate::Error> { |
760 | self.parse(cmd, arg, value) |
761 | } |
762 | |
763 | /// Reflect on enumerated value properties |
764 | /// |
765 | /// Error checking should not be done with this; it is mostly targeted at user-facing |
766 | /// applications like errors and completion. |
767 | fn possible_values( |
768 | &self, |
769 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
770 | None |
771 | } |
772 | |
773 | /// Adapt a `TypedValueParser` from one value to another |
774 | /// |
775 | /// # Example |
776 | /// |
777 | /// ```rust |
778 | /// # use clap_builder as clap; |
779 | /// # use clap::Command; |
780 | /// # use clap::Arg; |
781 | /// # use clap::builder::TypedValueParser as _; |
782 | /// # use clap::builder::BoolishValueParser; |
783 | /// let cmd = Command::new("mycmd" ) |
784 | /// .arg( |
785 | /// Arg::new("flag" ) |
786 | /// .long("flag" ) |
787 | /// .action(clap::ArgAction::SetTrue) |
788 | /// .value_parser( |
789 | /// BoolishValueParser::new() |
790 | /// .map(|b| -> usize { |
791 | /// if b { 10 } else { 5 } |
792 | /// }) |
793 | /// ) |
794 | /// ); |
795 | /// |
796 | /// let matches = cmd.clone().try_get_matches_from(["mycmd" , "--flag" ]).unwrap(); |
797 | /// assert!(matches.contains_id("flag" )); |
798 | /// assert_eq!( |
799 | /// matches.get_one::<usize>("flag" ).copied(), |
800 | /// Some(10) |
801 | /// ); |
802 | /// |
803 | /// let matches = cmd.try_get_matches_from(["mycmd" ]).unwrap(); |
804 | /// assert!(matches.contains_id("flag" )); |
805 | /// assert_eq!( |
806 | /// matches.get_one::<usize>("flag" ).copied(), |
807 | /// Some(5) |
808 | /// ); |
809 | /// ``` |
810 | fn map<T, F>(self, func: F) -> MapValueParser<Self, F> |
811 | where |
812 | T: Send + Sync + Clone, |
813 | F: Fn(Self::Value) -> T + Clone, |
814 | { |
815 | MapValueParser::new(self, func) |
816 | } |
817 | |
818 | /// Adapt a `TypedValueParser` from one value to another |
819 | /// |
820 | /// # Example |
821 | /// |
822 | /// ```rust |
823 | /// # use clap_builder as clap; |
824 | /// # use std::ffi::OsString; |
825 | /// # use std::ffi::OsStr; |
826 | /// # use std::path::PathBuf; |
827 | /// # use std::path::Path; |
828 | /// # use clap::Command; |
829 | /// # use clap::Arg; |
830 | /// # use clap::builder::TypedValueParser as _; |
831 | /// # use clap::builder::OsStringValueParser; |
832 | /// let cmd = Command::new("mycmd" ) |
833 | /// .arg( |
834 | /// Arg::new("flag" ) |
835 | /// .long("flag" ) |
836 | /// .value_parser( |
837 | /// OsStringValueParser::new() |
838 | /// .try_map(verify_ext) |
839 | /// ) |
840 | /// ); |
841 | /// |
842 | /// fn verify_ext(os: OsString) -> Result<PathBuf, &'static str> { |
843 | /// let path = PathBuf::from(os); |
844 | /// if path.extension() != Some(OsStr::new("rs" )) { |
845 | /// return Err("only Rust files are supported" ); |
846 | /// } |
847 | /// Ok(path) |
848 | /// } |
849 | /// |
850 | /// let error = cmd.clone().try_get_matches_from(["mycmd" , "--flag" , "foo.txt" ]).unwrap_err(); |
851 | /// error.print(); |
852 | /// |
853 | /// let matches = cmd.try_get_matches_from(["mycmd" , "--flag" , "foo.rs" ]).unwrap(); |
854 | /// assert!(matches.contains_id("flag" )); |
855 | /// assert_eq!( |
856 | /// matches.get_one::<PathBuf>("flag" ).map(|s| s.as_path()), |
857 | /// Some(Path::new("foo.rs" )) |
858 | /// ); |
859 | /// ``` |
860 | fn try_map<T, E, F>(self, func: F) -> TryMapValueParser<Self, F> |
861 | where |
862 | F: Fn(Self::Value) -> Result<T, E> + Clone + Send + Sync + 'static, |
863 | T: Send + Sync + Clone, |
864 | E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
865 | { |
866 | TryMapValueParser::new(self, func) |
867 | } |
868 | } |
869 | |
870 | impl<F, T, E> TypedValueParser for F |
871 | where |
872 | F: Fn(&str) -> Result<T, E> + Clone + Send + Sync + 'static, |
873 | E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
874 | T: Send + Sync + Clone, |
875 | { |
876 | type Value = T; |
877 | |
878 | fn parse_ref( |
879 | &self, |
880 | cmd: &crate::Command, |
881 | arg: Option<&crate::Arg>, |
882 | value: &std::ffi::OsStr, |
883 | ) -> Result<Self::Value, crate::Error> { |
884 | let value: &str = ok!(value.to_str().ok_or_else(|| { |
885 | crate::Error::invalid_utf8( |
886 | cmd, |
887 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
888 | ) |
889 | })); |
890 | let value: T = ok!((self)(value).map_err(|e| { |
891 | let arg = arg |
892 | .map(|a| a.to_string()) |
893 | .unwrap_or_else(|| "..." .to_owned()); |
894 | crate::Error::value_validation(arg, value.to_owned(), e.into()).with_cmd(cmd) |
895 | })); |
896 | Ok(value) |
897 | } |
898 | } |
899 | |
900 | /// Implementation for [`ValueParser::string`] |
901 | /// |
902 | /// Useful for composing new [`TypedValueParser`]s |
903 | #[derive (Copy, Clone, Debug)] |
904 | #[non_exhaustive ] |
905 | pub struct StringValueParser {} |
906 | |
907 | impl StringValueParser { |
908 | /// Implementation for [`ValueParser::string`] |
909 | pub fn new() -> Self { |
910 | Self {} |
911 | } |
912 | } |
913 | |
914 | impl TypedValueParser for StringValueParser { |
915 | type Value = String; |
916 | |
917 | fn parse_ref( |
918 | &self, |
919 | cmd: &crate::Command, |
920 | arg: Option<&crate::Arg>, |
921 | value: &std::ffi::OsStr, |
922 | ) -> Result<Self::Value, crate::Error> { |
923 | TypedValueParser::parse(self, cmd, arg, value.to_owned()) |
924 | } |
925 | |
926 | fn parse( |
927 | &self, |
928 | cmd: &crate::Command, |
929 | _arg: Option<&crate::Arg>, |
930 | value: std::ffi::OsString, |
931 | ) -> Result<Self::Value, crate::Error> { |
932 | let value = ok!(value.into_string().map_err(|_| { |
933 | crate::Error::invalid_utf8( |
934 | cmd, |
935 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
936 | ) |
937 | })); |
938 | Ok(value) |
939 | } |
940 | } |
941 | |
942 | impl Default for StringValueParser { |
943 | fn default() -> Self { |
944 | Self::new() |
945 | } |
946 | } |
947 | |
948 | /// Implementation for [`ValueParser::os_string`] |
949 | /// |
950 | /// Useful for composing new [`TypedValueParser`]s |
951 | #[derive (Copy, Clone, Debug)] |
952 | #[non_exhaustive ] |
953 | pub struct OsStringValueParser {} |
954 | |
955 | impl OsStringValueParser { |
956 | /// Implementation for [`ValueParser::os_string`] |
957 | pub fn new() -> Self { |
958 | Self {} |
959 | } |
960 | } |
961 | |
962 | impl TypedValueParser for OsStringValueParser { |
963 | type Value = std::ffi::OsString; |
964 | |
965 | fn parse_ref( |
966 | &self, |
967 | cmd: &crate::Command, |
968 | arg: Option<&crate::Arg>, |
969 | value: &std::ffi::OsStr, |
970 | ) -> Result<Self::Value, crate::Error> { |
971 | TypedValueParser::parse(self, cmd, arg, value.to_owned()) |
972 | } |
973 | |
974 | fn parse( |
975 | &self, |
976 | _cmd: &crate::Command, |
977 | _arg: Option<&crate::Arg>, |
978 | value: std::ffi::OsString, |
979 | ) -> Result<Self::Value, crate::Error> { |
980 | Ok(value) |
981 | } |
982 | } |
983 | |
984 | impl Default for OsStringValueParser { |
985 | fn default() -> Self { |
986 | Self::new() |
987 | } |
988 | } |
989 | |
990 | /// Implementation for [`ValueParser::path_buf`] |
991 | /// |
992 | /// Useful for composing new [`TypedValueParser`]s |
993 | #[derive (Copy, Clone, Debug)] |
994 | #[non_exhaustive ] |
995 | pub struct PathBufValueParser {} |
996 | |
997 | impl PathBufValueParser { |
998 | /// Implementation for [`ValueParser::path_buf`] |
999 | pub fn new() -> Self { |
1000 | Self {} |
1001 | } |
1002 | } |
1003 | |
1004 | impl TypedValueParser for PathBufValueParser { |
1005 | type Value = std::path::PathBuf; |
1006 | |
1007 | fn parse_ref( |
1008 | &self, |
1009 | cmd: &crate::Command, |
1010 | arg: Option<&crate::Arg>, |
1011 | value: &std::ffi::OsStr, |
1012 | ) -> Result<Self::Value, crate::Error> { |
1013 | TypedValueParser::parse(self, cmd, arg, value.to_owned()) |
1014 | } |
1015 | |
1016 | fn parse( |
1017 | &self, |
1018 | cmd: &crate::Command, |
1019 | arg: Option<&crate::Arg>, |
1020 | value: std::ffi::OsString, |
1021 | ) -> Result<Self::Value, crate::Error> { |
1022 | if value.is_empty() { |
1023 | return Err(crate::Error::empty_value( |
1024 | cmd, |
1025 | &[], |
1026 | arg.map(ToString::to_string) |
1027 | .unwrap_or_else(|| "..." .to_owned()), |
1028 | )); |
1029 | } |
1030 | Ok(Self::Value::from(value)) |
1031 | } |
1032 | } |
1033 | |
1034 | impl Default for PathBufValueParser { |
1035 | fn default() -> Self { |
1036 | Self::new() |
1037 | } |
1038 | } |
1039 | |
1040 | /// Parse an [`ValueEnum`][crate::ValueEnum] value. |
1041 | /// |
1042 | /// See also: |
1043 | /// - [`PossibleValuesParser`] |
1044 | /// |
1045 | /// # Example |
1046 | /// |
1047 | /// ```rust |
1048 | /// # use clap_builder as clap; |
1049 | /// # use std::ffi::OsStr; |
1050 | /// # use clap::ColorChoice; |
1051 | /// # use clap::builder::TypedValueParser; |
1052 | /// # let cmd = clap::Command::new("test" ); |
1053 | /// # let arg = None; |
1054 | /// |
1055 | /// // Usage |
1056 | /// let mut cmd = clap::Command::new("raw" ) |
1057 | /// .arg( |
1058 | /// clap::Arg::new("color" ) |
1059 | /// .value_parser(clap::builder::EnumValueParser::<ColorChoice>::new()) |
1060 | /// .required(true) |
1061 | /// ); |
1062 | /// |
1063 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "always" ]).unwrap(); |
1064 | /// let port: ColorChoice = *m.get_one("color" ) |
1065 | /// .expect("required" ); |
1066 | /// assert_eq!(port, ColorChoice::Always); |
1067 | /// |
1068 | /// // Semantics |
1069 | /// let value_parser = clap::builder::EnumValueParser::<ColorChoice>::new(); |
1070 | /// // or |
1071 | /// let value_parser = clap::value_parser!(ColorChoice); |
1072 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1073 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1074 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("always" )).unwrap(), ColorChoice::Always); |
1075 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("auto" )).unwrap(), ColorChoice::Auto); |
1076 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("never" )).unwrap(), ColorChoice::Never); |
1077 | /// ``` |
1078 | #[derive (Clone, Debug)] |
1079 | pub struct EnumValueParser<E: crate::ValueEnum + Clone + Send + Sync + 'static>( |
1080 | std::marker::PhantomData<E>, |
1081 | ); |
1082 | |
1083 | impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> EnumValueParser<E> { |
1084 | /// Parse an [`ValueEnum`][crate::ValueEnum] |
1085 | pub fn new() -> Self { |
1086 | let phantom: std::marker::PhantomData<E> = Default::default(); |
1087 | Self(phantom) |
1088 | } |
1089 | } |
1090 | |
1091 | impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> TypedValueParser for EnumValueParser<E> { |
1092 | type Value = E; |
1093 | |
1094 | fn parse_ref( |
1095 | &self, |
1096 | cmd: &crate::Command, |
1097 | arg: Option<&crate::Arg>, |
1098 | value: &std::ffi::OsStr, |
1099 | ) -> Result<Self::Value, crate::Error> { |
1100 | let ignore_case = arg.map(|a| a.is_ignore_case_set()).unwrap_or(false); |
1101 | let possible_vals = || { |
1102 | E::value_variants() |
1103 | .iter() |
1104 | .filter_map(|v| v.to_possible_value()) |
1105 | .filter(|v| !v.is_hide_set()) |
1106 | .map(|v| v.get_name().to_owned()) |
1107 | .collect::<Vec<_>>() |
1108 | }; |
1109 | |
1110 | let value = ok!(value.to_str().ok_or_else(|| { |
1111 | crate::Error::invalid_value( |
1112 | cmd, |
1113 | value.to_string_lossy().into_owned(), |
1114 | &possible_vals(), |
1115 | arg.map(ToString::to_string) |
1116 | .unwrap_or_else(|| "..." .to_owned()), |
1117 | ) |
1118 | })); |
1119 | let value = ok!(E::value_variants() |
1120 | .iter() |
1121 | .find(|v| { |
1122 | v.to_possible_value() |
1123 | .expect("ValueEnum::value_variants contains only values with a corresponding ValueEnum::to_possible_value" ) |
1124 | .matches(value, ignore_case) |
1125 | }) |
1126 | .ok_or_else(|| { |
1127 | crate::Error::invalid_value( |
1128 | cmd, |
1129 | value.to_owned(), |
1130 | &possible_vals(), |
1131 | arg.map(ToString::to_string) |
1132 | .unwrap_or_else(|| "..." .to_owned()), |
1133 | ) |
1134 | })) |
1135 | .clone(); |
1136 | Ok(value) |
1137 | } |
1138 | |
1139 | fn possible_values( |
1140 | &self, |
1141 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1142 | Some(Box::new( |
1143 | E::value_variants() |
1144 | .iter() |
1145 | .filter_map(|v| v.to_possible_value()), |
1146 | )) |
1147 | } |
1148 | } |
1149 | |
1150 | impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> Default for EnumValueParser<E> { |
1151 | fn default() -> Self { |
1152 | Self::new() |
1153 | } |
1154 | } |
1155 | |
1156 | /// Verify the value is from an enumerated set of [`PossibleValue`][crate::builder::PossibleValue]. |
1157 | /// |
1158 | /// See also: |
1159 | /// - [`EnumValueParser`] for directly supporting [`ValueEnum`][crate::ValueEnum] types |
1160 | /// - [`TypedValueParser::map`] for adapting values to a more specialized type, like an external |
1161 | /// enums that can't implement [`ValueEnum`][crate::ValueEnum] |
1162 | /// |
1163 | /// # Example |
1164 | /// |
1165 | /// Usage: |
1166 | /// ```rust |
1167 | /// # use clap_builder as clap; |
1168 | /// let mut cmd = clap::Command::new("raw" ) |
1169 | /// .arg( |
1170 | /// clap::Arg::new("color" ) |
1171 | /// .value_parser(clap::builder::PossibleValuesParser::new(["always" , "auto" , "never" ])) |
1172 | /// .required(true) |
1173 | /// ); |
1174 | /// |
1175 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "always" ]).unwrap(); |
1176 | /// let port: &String = m.get_one("color" ) |
1177 | /// .expect("required" ); |
1178 | /// assert_eq!(port, "always" ); |
1179 | /// ``` |
1180 | /// |
1181 | /// Semantics: |
1182 | /// ```rust |
1183 | /// # use clap_builder as clap; |
1184 | /// # use std::ffi::OsStr; |
1185 | /// # use clap::builder::TypedValueParser; |
1186 | /// # let cmd = clap::Command::new("test" ); |
1187 | /// # let arg = None; |
1188 | /// let value_parser = clap::builder::PossibleValuesParser::new(["always" , "auto" , "never" ]); |
1189 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1190 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1191 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("always" )).unwrap(), "always" ); |
1192 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("auto" )).unwrap(), "auto" ); |
1193 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("never" )).unwrap(), "never" ); |
1194 | /// ``` |
1195 | #[derive (Clone, Debug)] |
1196 | pub struct PossibleValuesParser(Vec<super::PossibleValue>); |
1197 | |
1198 | impl PossibleValuesParser { |
1199 | /// Verify the value is from an enumerated set of [`PossibleValue`][crate::builder::PossibleValue]. |
1200 | pub fn new(values: impl Into<PossibleValuesParser>) -> Self { |
1201 | values.into() |
1202 | } |
1203 | } |
1204 | |
1205 | impl TypedValueParser for PossibleValuesParser { |
1206 | type Value = String; |
1207 | |
1208 | fn parse_ref( |
1209 | &self, |
1210 | cmd: &crate::Command, |
1211 | arg: Option<&crate::Arg>, |
1212 | value: &std::ffi::OsStr, |
1213 | ) -> Result<Self::Value, crate::Error> { |
1214 | TypedValueParser::parse(self, cmd, arg, value.to_owned()) |
1215 | } |
1216 | |
1217 | fn parse( |
1218 | &self, |
1219 | cmd: &crate::Command, |
1220 | arg: Option<&crate::Arg>, |
1221 | value: std::ffi::OsString, |
1222 | ) -> Result<String, crate::Error> { |
1223 | let value = ok!(value.into_string().map_err(|_| { |
1224 | crate::Error::invalid_utf8( |
1225 | cmd, |
1226 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1227 | ) |
1228 | })); |
1229 | |
1230 | let ignore_case = arg.map(|a| a.is_ignore_case_set()).unwrap_or(false); |
1231 | if self.0.iter().any(|v| v.matches(&value, ignore_case)) { |
1232 | Ok(value) |
1233 | } else { |
1234 | let possible_vals = self |
1235 | .0 |
1236 | .iter() |
1237 | .filter(|v| !v.is_hide_set()) |
1238 | .map(|v| v.get_name().to_owned()) |
1239 | .collect::<Vec<_>>(); |
1240 | |
1241 | Err(crate::Error::invalid_value( |
1242 | cmd, |
1243 | value, |
1244 | &possible_vals, |
1245 | arg.map(ToString::to_string) |
1246 | .unwrap_or_else(|| "..." .to_owned()), |
1247 | )) |
1248 | } |
1249 | } |
1250 | |
1251 | fn possible_values( |
1252 | &self, |
1253 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1254 | Some(Box::new(self.0.iter().cloned())) |
1255 | } |
1256 | } |
1257 | |
1258 | impl<I, T> From<I> for PossibleValuesParser |
1259 | where |
1260 | I: IntoIterator<Item = T>, |
1261 | T: Into<super::PossibleValue>, |
1262 | { |
1263 | fn from(values: I) -> Self { |
1264 | Self(values.into_iter().map(|t: T| t.into()).collect()) |
1265 | } |
1266 | } |
1267 | |
1268 | /// Parse number that fall within a range of values |
1269 | /// |
1270 | /// <div class="warning"> |
1271 | /// |
1272 | /// **NOTE:** To capture negative values, you will also need to set |
1273 | /// [`Arg::allow_negative_numbers`][crate::Arg::allow_negative_numbers] or |
1274 | /// [`Arg::allow_hyphen_values`][crate::Arg::allow_hyphen_values]. |
1275 | /// |
1276 | /// </div> |
1277 | /// |
1278 | /// # Example |
1279 | /// |
1280 | /// Usage: |
1281 | /// ```rust |
1282 | /// # use clap_builder as clap; |
1283 | /// let mut cmd = clap::Command::new("raw" ) |
1284 | /// .arg( |
1285 | /// clap::Arg::new("port" ) |
1286 | /// .long("port" ) |
1287 | /// .value_parser(clap::value_parser!(u16).range(3000..)) |
1288 | /// .action(clap::ArgAction::Set) |
1289 | /// .required(true) |
1290 | /// ); |
1291 | /// |
1292 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "3001" ]).unwrap(); |
1293 | /// let port: u16 = *m.get_one("port" ) |
1294 | /// .expect("required" ); |
1295 | /// assert_eq!(port, 3001); |
1296 | /// ``` |
1297 | /// |
1298 | /// Semantics: |
1299 | /// ```rust |
1300 | /// # use clap_builder as clap; |
1301 | /// # use std::ffi::OsStr; |
1302 | /// # use clap::builder::TypedValueParser; |
1303 | /// # let cmd = clap::Command::new("test" ); |
1304 | /// # let arg = None; |
1305 | /// let value_parser = clap::builder::RangedI64ValueParser::<i32>::new().range(-1..200); |
1306 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1307 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1308 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-200" )).is_err()); |
1309 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("300" )).is_err()); |
1310 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("-1" )).unwrap(), -1); |
1311 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0" )).unwrap(), 0); |
1312 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50" )).unwrap(), 50); |
1313 | /// ``` |
1314 | #[derive (Copy, Clone, Debug)] |
1315 | pub struct RangedI64ValueParser<T: TryFrom<i64> + Clone + Send + Sync = i64> { |
1316 | bounds: (std::ops::Bound<i64>, std::ops::Bound<i64>), |
1317 | target: std::marker::PhantomData<T>, |
1318 | } |
1319 | |
1320 | impl<T: TryFrom<i64> + Clone + Send + Sync> RangedI64ValueParser<T> { |
1321 | /// Select full range of `i64` |
1322 | pub fn new() -> Self { |
1323 | Self::from(..) |
1324 | } |
1325 | |
1326 | /// Narrow the supported range |
1327 | pub fn range<B: RangeBounds<i64>>(mut self, range: B) -> Self { |
1328 | // Consideration: when the user does `value_parser!(u8).range()` |
1329 | // - Avoid programming mistakes by accidentally expanding the range |
1330 | // - Make it convenient to limit the range like with `..10` |
1331 | let start = match range.start_bound() { |
1332 | l @ std::ops::Bound::Included(i) => { |
1333 | debug_assert!( |
1334 | self.bounds.contains(i), |
1335 | " {} must be in {:?}" , |
1336 | i, |
1337 | self.bounds |
1338 | ); |
1339 | l.cloned() |
1340 | } |
1341 | l @ std::ops::Bound::Excluded(i) => { |
1342 | debug_assert!( |
1343 | self.bounds.contains(&i.saturating_add(1)), |
1344 | " {} must be in {:?}" , |
1345 | i, |
1346 | self.bounds |
1347 | ); |
1348 | l.cloned() |
1349 | } |
1350 | std::ops::Bound::Unbounded => self.bounds.start_bound().cloned(), |
1351 | }; |
1352 | let end = match range.end_bound() { |
1353 | l @ std::ops::Bound::Included(i) => { |
1354 | debug_assert!( |
1355 | self.bounds.contains(i), |
1356 | " {} must be in {:?}" , |
1357 | i, |
1358 | self.bounds |
1359 | ); |
1360 | l.cloned() |
1361 | } |
1362 | l @ std::ops::Bound::Excluded(i) => { |
1363 | debug_assert!( |
1364 | self.bounds.contains(&i.saturating_sub(1)), |
1365 | " {} must be in {:?}" , |
1366 | i, |
1367 | self.bounds |
1368 | ); |
1369 | l.cloned() |
1370 | } |
1371 | std::ops::Bound::Unbounded => self.bounds.end_bound().cloned(), |
1372 | }; |
1373 | self.bounds = (start, end); |
1374 | self |
1375 | } |
1376 | |
1377 | fn format_bounds(&self) -> String { |
1378 | let mut result = match self.bounds.0 { |
1379 | std::ops::Bound::Included(i) => i.to_string(), |
1380 | std::ops::Bound::Excluded(i) => i.saturating_add(1).to_string(), |
1381 | std::ops::Bound::Unbounded => i64::MIN.to_string(), |
1382 | }; |
1383 | result.push_str(".." ); |
1384 | match self.bounds.1 { |
1385 | std::ops::Bound::Included(i) => { |
1386 | result.push('=' ); |
1387 | result.push_str(&i.to_string()); |
1388 | } |
1389 | std::ops::Bound::Excluded(i) => { |
1390 | result.push_str(&i.to_string()); |
1391 | } |
1392 | std::ops::Bound::Unbounded => { |
1393 | result.push_str(&i64::MAX.to_string()); |
1394 | } |
1395 | } |
1396 | result |
1397 | } |
1398 | } |
1399 | |
1400 | impl<T: TryFrom<i64> + Clone + Send + Sync + 'static> TypedValueParser for RangedI64ValueParser<T> |
1401 | where |
1402 | <T as TryFrom<i64>>::Error: Send + Sync + 'static + std::error::Error + ToString, |
1403 | { |
1404 | type Value = T; |
1405 | |
1406 | fn parse_ref( |
1407 | &self, |
1408 | cmd: &crate::Command, |
1409 | arg: Option<&crate::Arg>, |
1410 | raw_value: &std::ffi::OsStr, |
1411 | ) -> Result<Self::Value, crate::Error> { |
1412 | let value = ok!(raw_value.to_str().ok_or_else(|| { |
1413 | crate::Error::invalid_utf8( |
1414 | cmd, |
1415 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1416 | ) |
1417 | })); |
1418 | let value = ok!(value.parse::<i64>().map_err(|err| { |
1419 | let arg = arg |
1420 | .map(|a| a.to_string()) |
1421 | .unwrap_or_else(|| "..." .to_owned()); |
1422 | crate::Error::value_validation( |
1423 | arg, |
1424 | raw_value.to_string_lossy().into_owned(), |
1425 | err.into(), |
1426 | ) |
1427 | .with_cmd(cmd) |
1428 | })); |
1429 | if !self.bounds.contains(&value) { |
1430 | let arg = arg |
1431 | .map(|a| a.to_string()) |
1432 | .unwrap_or_else(|| "..." .to_owned()); |
1433 | return Err(crate::Error::value_validation( |
1434 | arg, |
1435 | raw_value.to_string_lossy().into_owned(), |
1436 | format!(" {} is not in {}" , value, self.format_bounds()).into(), |
1437 | ) |
1438 | .with_cmd(cmd)); |
1439 | } |
1440 | |
1441 | let value: Result<Self::Value, _> = value.try_into(); |
1442 | let value = ok!(value.map_err(|err| { |
1443 | let arg = arg |
1444 | .map(|a| a.to_string()) |
1445 | .unwrap_or_else(|| "..." .to_owned()); |
1446 | crate::Error::value_validation( |
1447 | arg, |
1448 | raw_value.to_string_lossy().into_owned(), |
1449 | err.into(), |
1450 | ) |
1451 | .with_cmd(cmd) |
1452 | })); |
1453 | |
1454 | Ok(value) |
1455 | } |
1456 | } |
1457 | |
1458 | impl<T: TryFrom<i64> + Clone + Send + Sync, B: RangeBounds<i64>> From<B> |
1459 | for RangedI64ValueParser<T> |
1460 | { |
1461 | fn from(range: B) -> Self { |
1462 | Self { |
1463 | bounds: (range.start_bound().cloned(), range.end_bound().cloned()), |
1464 | target: Default::default(), |
1465 | } |
1466 | } |
1467 | } |
1468 | |
1469 | impl<T: TryFrom<i64> + Clone + Send + Sync> Default for RangedI64ValueParser<T> { |
1470 | fn default() -> Self { |
1471 | Self::new() |
1472 | } |
1473 | } |
1474 | |
1475 | /// Parse number that fall within a range of values |
1476 | /// |
1477 | /// # Example |
1478 | /// |
1479 | /// Usage: |
1480 | /// ```rust |
1481 | /// # use clap_builder as clap; |
1482 | /// let mut cmd = clap::Command::new("raw" ) |
1483 | /// .arg( |
1484 | /// clap::Arg::new("port" ) |
1485 | /// .long("port" ) |
1486 | /// .value_parser(clap::value_parser!(u64).range(3000..)) |
1487 | /// .action(clap::ArgAction::Set) |
1488 | /// .required(true) |
1489 | /// ); |
1490 | /// |
1491 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "--port" , "3001" ]).unwrap(); |
1492 | /// let port: u64 = *m.get_one("port" ) |
1493 | /// .expect("required" ); |
1494 | /// assert_eq!(port, 3001); |
1495 | /// ``` |
1496 | /// |
1497 | /// Semantics: |
1498 | /// ```rust |
1499 | /// # use clap_builder as clap; |
1500 | /// # use std::ffi::OsStr; |
1501 | /// # use clap::builder::TypedValueParser; |
1502 | /// # let cmd = clap::Command::new("test" ); |
1503 | /// # let arg = None; |
1504 | /// let value_parser = clap::builder::RangedU64ValueParser::<u32>::new().range(0..200); |
1505 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1506 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1507 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-200" )).is_err()); |
1508 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("300" )).is_err()); |
1509 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-1" )).is_err()); |
1510 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0" )).unwrap(), 0); |
1511 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50" )).unwrap(), 50); |
1512 | /// ``` |
1513 | #[derive (Copy, Clone, Debug)] |
1514 | pub struct RangedU64ValueParser<T: TryFrom<u64> = u64> { |
1515 | bounds: (std::ops::Bound<u64>, std::ops::Bound<u64>), |
1516 | target: std::marker::PhantomData<T>, |
1517 | } |
1518 | |
1519 | impl<T: TryFrom<u64>> RangedU64ValueParser<T> { |
1520 | /// Select full range of `u64` |
1521 | pub fn new() -> Self { |
1522 | Self::from(..) |
1523 | } |
1524 | |
1525 | /// Narrow the supported range |
1526 | pub fn range<B: RangeBounds<u64>>(mut self, range: B) -> Self { |
1527 | // Consideration: when the user does `value_parser!(u8).range()` |
1528 | // - Avoid programming mistakes by accidentally expanding the range |
1529 | // - Make it convenient to limit the range like with `..10` |
1530 | let start = match range.start_bound() { |
1531 | l @ std::ops::Bound::Included(i) => { |
1532 | debug_assert!( |
1533 | self.bounds.contains(i), |
1534 | " {} must be in {:?}" , |
1535 | i, |
1536 | self.bounds |
1537 | ); |
1538 | l.cloned() |
1539 | } |
1540 | l @ std::ops::Bound::Excluded(i) => { |
1541 | debug_assert!( |
1542 | self.bounds.contains(&i.saturating_add(1)), |
1543 | " {} must be in {:?}" , |
1544 | i, |
1545 | self.bounds |
1546 | ); |
1547 | l.cloned() |
1548 | } |
1549 | std::ops::Bound::Unbounded => self.bounds.start_bound().cloned(), |
1550 | }; |
1551 | let end = match range.end_bound() { |
1552 | l @ std::ops::Bound::Included(i) => { |
1553 | debug_assert!( |
1554 | self.bounds.contains(i), |
1555 | " {} must be in {:?}" , |
1556 | i, |
1557 | self.bounds |
1558 | ); |
1559 | l.cloned() |
1560 | } |
1561 | l @ std::ops::Bound::Excluded(i) => { |
1562 | debug_assert!( |
1563 | self.bounds.contains(&i.saturating_sub(1)), |
1564 | " {} must be in {:?}" , |
1565 | i, |
1566 | self.bounds |
1567 | ); |
1568 | l.cloned() |
1569 | } |
1570 | std::ops::Bound::Unbounded => self.bounds.end_bound().cloned(), |
1571 | }; |
1572 | self.bounds = (start, end); |
1573 | self |
1574 | } |
1575 | |
1576 | fn format_bounds(&self) -> String { |
1577 | let mut result = match self.bounds.0 { |
1578 | std::ops::Bound::Included(i) => i.to_string(), |
1579 | std::ops::Bound::Excluded(i) => i.saturating_add(1).to_string(), |
1580 | std::ops::Bound::Unbounded => u64::MIN.to_string(), |
1581 | }; |
1582 | result.push_str(".." ); |
1583 | match self.bounds.1 { |
1584 | std::ops::Bound::Included(i) => { |
1585 | result.push('=' ); |
1586 | result.push_str(&i.to_string()); |
1587 | } |
1588 | std::ops::Bound::Excluded(i) => { |
1589 | result.push_str(&i.to_string()); |
1590 | } |
1591 | std::ops::Bound::Unbounded => { |
1592 | result.push_str(&u64::MAX.to_string()); |
1593 | } |
1594 | } |
1595 | result |
1596 | } |
1597 | } |
1598 | |
1599 | impl<T: TryFrom<u64> + Clone + Send + Sync + 'static> TypedValueParser for RangedU64ValueParser<T> |
1600 | where |
1601 | <T as TryFrom<u64>>::Error: Send + Sync + 'static + std::error::Error + ToString, |
1602 | { |
1603 | type Value = T; |
1604 | |
1605 | fn parse_ref( |
1606 | &self, |
1607 | cmd: &crate::Command, |
1608 | arg: Option<&crate::Arg>, |
1609 | raw_value: &std::ffi::OsStr, |
1610 | ) -> Result<Self::Value, crate::Error> { |
1611 | let value = ok!(raw_value.to_str().ok_or_else(|| { |
1612 | crate::Error::invalid_utf8( |
1613 | cmd, |
1614 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1615 | ) |
1616 | })); |
1617 | let value = ok!(value.parse::<u64>().map_err(|err| { |
1618 | let arg = arg |
1619 | .map(|a| a.to_string()) |
1620 | .unwrap_or_else(|| "..." .to_owned()); |
1621 | crate::Error::value_validation( |
1622 | arg, |
1623 | raw_value.to_string_lossy().into_owned(), |
1624 | err.into(), |
1625 | ) |
1626 | .with_cmd(cmd) |
1627 | })); |
1628 | if !self.bounds.contains(&value) { |
1629 | let arg = arg |
1630 | .map(|a| a.to_string()) |
1631 | .unwrap_or_else(|| "..." .to_owned()); |
1632 | return Err(crate::Error::value_validation( |
1633 | arg, |
1634 | raw_value.to_string_lossy().into_owned(), |
1635 | format!(" {} is not in {}" , value, self.format_bounds()).into(), |
1636 | ) |
1637 | .with_cmd(cmd)); |
1638 | } |
1639 | |
1640 | let value: Result<Self::Value, _> = value.try_into(); |
1641 | let value = ok!(value.map_err(|err| { |
1642 | let arg = arg |
1643 | .map(|a| a.to_string()) |
1644 | .unwrap_or_else(|| "..." .to_owned()); |
1645 | crate::Error::value_validation( |
1646 | arg, |
1647 | raw_value.to_string_lossy().into_owned(), |
1648 | err.into(), |
1649 | ) |
1650 | .with_cmd(cmd) |
1651 | })); |
1652 | |
1653 | Ok(value) |
1654 | } |
1655 | } |
1656 | |
1657 | impl<T: TryFrom<u64>, B: RangeBounds<u64>> From<B> for RangedU64ValueParser<T> { |
1658 | fn from(range: B) -> Self { |
1659 | Self { |
1660 | bounds: (range.start_bound().cloned(), range.end_bound().cloned()), |
1661 | target: Default::default(), |
1662 | } |
1663 | } |
1664 | } |
1665 | |
1666 | impl<T: TryFrom<u64>> Default for RangedU64ValueParser<T> { |
1667 | fn default() -> Self { |
1668 | Self::new() |
1669 | } |
1670 | } |
1671 | |
1672 | /// Implementation for [`ValueParser::bool`] |
1673 | /// |
1674 | /// Useful for composing new [`TypedValueParser`]s |
1675 | #[derive (Copy, Clone, Debug)] |
1676 | #[non_exhaustive ] |
1677 | pub struct BoolValueParser {} |
1678 | |
1679 | impl BoolValueParser { |
1680 | /// Implementation for [`ValueParser::bool`] |
1681 | pub fn new() -> Self { |
1682 | Self {} |
1683 | } |
1684 | |
1685 | fn possible_values() -> impl Iterator<Item = crate::builder::PossibleValue> { |
1686 | ["true" , "false" ] |
1687 | .iter() |
1688 | .copied() |
1689 | .map(crate::builder::PossibleValue::new) |
1690 | } |
1691 | } |
1692 | |
1693 | impl TypedValueParser for BoolValueParser { |
1694 | type Value = bool; |
1695 | |
1696 | fn parse_ref( |
1697 | &self, |
1698 | cmd: &crate::Command, |
1699 | arg: Option<&crate::Arg>, |
1700 | value: &std::ffi::OsStr, |
1701 | ) -> Result<Self::Value, crate::Error> { |
1702 | let value = if value == std::ffi::OsStr::new("true" ) { |
1703 | true |
1704 | } else if value == std::ffi::OsStr::new("false" ) { |
1705 | false |
1706 | } else { |
1707 | // Intentionally showing hidden as we hide all of them |
1708 | let possible_vals = Self::possible_values() |
1709 | .map(|v| v.get_name().to_owned()) |
1710 | .collect::<Vec<_>>(); |
1711 | |
1712 | return Err(crate::Error::invalid_value( |
1713 | cmd, |
1714 | value.to_string_lossy().into_owned(), |
1715 | &possible_vals, |
1716 | arg.map(ToString::to_string) |
1717 | .unwrap_or_else(|| "..." .to_owned()), |
1718 | )); |
1719 | }; |
1720 | Ok(value) |
1721 | } |
1722 | |
1723 | fn possible_values( |
1724 | &self, |
1725 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1726 | Some(Box::new(Self::possible_values())) |
1727 | } |
1728 | } |
1729 | |
1730 | impl Default for BoolValueParser { |
1731 | fn default() -> Self { |
1732 | Self::new() |
1733 | } |
1734 | } |
1735 | |
1736 | /// Parse false-like string values, everything else is `true` |
1737 | /// |
1738 | /// See also: |
1739 | /// - [`ValueParser::bool`] for assuming non-false is true |
1740 | /// - [`BoolishValueParser`] for different human readable bool representations |
1741 | /// |
1742 | /// # Example |
1743 | /// |
1744 | /// Usage: |
1745 | /// ```rust |
1746 | /// # use clap_builder as clap; |
1747 | /// let mut cmd = clap::Command::new("raw" ) |
1748 | /// .arg( |
1749 | /// clap::Arg::new("append" ) |
1750 | /// .value_parser(clap::builder::FalseyValueParser::new()) |
1751 | /// .required(true) |
1752 | /// ); |
1753 | /// |
1754 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "true" ]).unwrap(); |
1755 | /// let port: bool = *m.get_one("append" ) |
1756 | /// .expect("required" ); |
1757 | /// assert_eq!(port, true); |
1758 | /// ``` |
1759 | /// |
1760 | /// Semantics: |
1761 | /// ```rust |
1762 | /// # use clap_builder as clap; |
1763 | /// # use std::ffi::OsStr; |
1764 | /// # use clap::builder::TypedValueParser; |
1765 | /// # let cmd = clap::Command::new("test" ); |
1766 | /// # let arg = None; |
1767 | /// let value_parser = clap::builder::FalseyValueParser::new(); |
1768 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).unwrap(), true); |
1769 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("100" )).unwrap(), true); |
1770 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).unwrap(), false); |
1771 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("false" )).unwrap(), false); |
1772 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("No" )).unwrap(), false); |
1773 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oFF" )).unwrap(), false); |
1774 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0" )).unwrap(), false); |
1775 | /// ``` |
1776 | #[derive (Copy, Clone, Debug)] |
1777 | #[non_exhaustive ] |
1778 | pub struct FalseyValueParser {} |
1779 | |
1780 | impl FalseyValueParser { |
1781 | /// Parse false-like string values, everything else is `true` |
1782 | pub fn new() -> Self { |
1783 | Self {} |
1784 | } |
1785 | |
1786 | fn possible_values() -> impl Iterator<Item = crate::builder::PossibleValue> { |
1787 | crateimpl Iterator ::util::TRUE_LITERALS |
1788 | .iter() |
1789 | .chain(crate::util::FALSE_LITERALS.iter()) |
1790 | .copied() |
1791 | .map(|l: &str| crate::builder::PossibleValue::new(l).hide(yes:l != "true" && l != "false" )) |
1792 | } |
1793 | } |
1794 | |
1795 | impl TypedValueParser for FalseyValueParser { |
1796 | type Value = bool; |
1797 | |
1798 | fn parse_ref( |
1799 | &self, |
1800 | cmd: &crate::Command, |
1801 | _arg: Option<&crate::Arg>, |
1802 | value: &std::ffi::OsStr, |
1803 | ) -> Result<Self::Value, crate::Error> { |
1804 | let value = ok!(value.to_str().ok_or_else(|| { |
1805 | crate::Error::invalid_utf8( |
1806 | cmd, |
1807 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1808 | ) |
1809 | })); |
1810 | let value = if value.is_empty() { |
1811 | false |
1812 | } else { |
1813 | crate::util::str_to_bool(value).unwrap_or(true) |
1814 | }; |
1815 | Ok(value) |
1816 | } |
1817 | |
1818 | fn possible_values( |
1819 | &self, |
1820 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1821 | Some(Box::new(Self::possible_values())) |
1822 | } |
1823 | } |
1824 | |
1825 | impl Default for FalseyValueParser { |
1826 | fn default() -> Self { |
1827 | Self::new() |
1828 | } |
1829 | } |
1830 | |
1831 | /// Parse bool-like string values |
1832 | /// |
1833 | /// See also: |
1834 | /// - [`ValueParser::bool`] for different human readable bool representations |
1835 | /// - [`FalseyValueParser`] for assuming non-false is true |
1836 | /// |
1837 | /// # Example |
1838 | /// |
1839 | /// Usage: |
1840 | /// ```rust |
1841 | /// # use clap_builder as clap; |
1842 | /// let mut cmd = clap::Command::new("raw" ) |
1843 | /// .arg( |
1844 | /// clap::Arg::new("append" ) |
1845 | /// .value_parser(clap::builder::BoolishValueParser::new()) |
1846 | /// .required(true) |
1847 | /// ); |
1848 | /// |
1849 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "true" ]).unwrap(); |
1850 | /// let port: bool = *m.get_one("append" ) |
1851 | /// .expect("required" ); |
1852 | /// assert_eq!(port, true); |
1853 | /// ``` |
1854 | /// |
1855 | /// Semantics: |
1856 | /// ```rust |
1857 | /// # use clap_builder as clap; |
1858 | /// # use std::ffi::OsStr; |
1859 | /// # use clap::builder::TypedValueParser; |
1860 | /// # let cmd = clap::Command::new("test" ); |
1861 | /// # let arg = None; |
1862 | /// let value_parser = clap::builder::BoolishValueParser::new(); |
1863 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).is_err()); |
1864 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1865 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("100" )).is_err()); |
1866 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("true" )).unwrap(), true); |
1867 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("Yes" )).unwrap(), true); |
1868 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oN" )).unwrap(), true); |
1869 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("1" )).unwrap(), true); |
1870 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("false" )).unwrap(), false); |
1871 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("No" )).unwrap(), false); |
1872 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oFF" )).unwrap(), false); |
1873 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0" )).unwrap(), false); |
1874 | /// ``` |
1875 | #[derive (Copy, Clone, Debug)] |
1876 | #[non_exhaustive ] |
1877 | pub struct BoolishValueParser {} |
1878 | |
1879 | impl BoolishValueParser { |
1880 | /// Parse bool-like string values |
1881 | pub fn new() -> Self { |
1882 | Self {} |
1883 | } |
1884 | |
1885 | fn possible_values() -> impl Iterator<Item = crate::builder::PossibleValue> { |
1886 | crateimpl Iterator ::util::TRUE_LITERALS |
1887 | .iter() |
1888 | .chain(crate::util::FALSE_LITERALS.iter()) |
1889 | .copied() |
1890 | .map(|l: &str| crate::builder::PossibleValue::new(l).hide(yes:l != "true" && l != "false" )) |
1891 | } |
1892 | } |
1893 | |
1894 | impl TypedValueParser for BoolishValueParser { |
1895 | type Value = bool; |
1896 | |
1897 | fn parse_ref( |
1898 | &self, |
1899 | cmd: &crate::Command, |
1900 | arg: Option<&crate::Arg>, |
1901 | value: &std::ffi::OsStr, |
1902 | ) -> Result<Self::Value, crate::Error> { |
1903 | let value = ok!(value.to_str().ok_or_else(|| { |
1904 | crate::Error::invalid_utf8( |
1905 | cmd, |
1906 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1907 | ) |
1908 | })); |
1909 | let value = ok!(crate::util::str_to_bool(value).ok_or_else(|| { |
1910 | let arg = arg |
1911 | .map(|a| a.to_string()) |
1912 | .unwrap_or_else(|| "..." .to_owned()); |
1913 | crate::Error::value_validation(arg, value.to_owned(), "value was not a boolean" .into()) |
1914 | .with_cmd(cmd) |
1915 | })); |
1916 | Ok(value) |
1917 | } |
1918 | |
1919 | fn possible_values( |
1920 | &self, |
1921 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
1922 | Some(Box::new(Self::possible_values())) |
1923 | } |
1924 | } |
1925 | |
1926 | impl Default for BoolishValueParser { |
1927 | fn default() -> Self { |
1928 | Self::new() |
1929 | } |
1930 | } |
1931 | |
1932 | /// Parse non-empty string values |
1933 | /// |
1934 | /// See also: |
1935 | /// - [`ValueParser::string`] |
1936 | /// |
1937 | /// # Example |
1938 | /// |
1939 | /// Usage: |
1940 | /// ```rust |
1941 | /// # use clap_builder as clap; |
1942 | /// let mut cmd = clap::Command::new("raw" ) |
1943 | /// .arg( |
1944 | /// clap::Arg::new("append" ) |
1945 | /// .value_parser(clap::builder::NonEmptyStringValueParser::new()) |
1946 | /// .required(true) |
1947 | /// ); |
1948 | /// |
1949 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "true" ]).unwrap(); |
1950 | /// let port: &String = m.get_one("append" ) |
1951 | /// .expect("required" ); |
1952 | /// assert_eq!(port, "true" ); |
1953 | /// ``` |
1954 | /// |
1955 | /// Semantics: |
1956 | /// ```rust |
1957 | /// # use clap_builder as clap; |
1958 | /// # use std::ffi::OsStr; |
1959 | /// # use clap::builder::TypedValueParser; |
1960 | /// # let cmd = clap::Command::new("test" ); |
1961 | /// # let arg = None; |
1962 | /// let value_parser = clap::builder::NonEmptyStringValueParser::new(); |
1963 | /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("random" )).unwrap(), "random" ); |
1964 | /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("" )).is_err()); |
1965 | /// ``` |
1966 | #[derive (Copy, Clone, Debug)] |
1967 | #[non_exhaustive ] |
1968 | pub struct NonEmptyStringValueParser {} |
1969 | |
1970 | impl NonEmptyStringValueParser { |
1971 | /// Parse non-empty string values |
1972 | pub fn new() -> Self { |
1973 | Self {} |
1974 | } |
1975 | } |
1976 | |
1977 | impl TypedValueParser for NonEmptyStringValueParser { |
1978 | type Value = String; |
1979 | |
1980 | fn parse_ref( |
1981 | &self, |
1982 | cmd: &crate::Command, |
1983 | arg: Option<&crate::Arg>, |
1984 | value: &std::ffi::OsStr, |
1985 | ) -> Result<Self::Value, crate::Error> { |
1986 | if value.is_empty() { |
1987 | return Err(crate::Error::empty_value( |
1988 | cmd, |
1989 | &[], |
1990 | arg.map(ToString::to_string) |
1991 | .unwrap_or_else(|| "..." .to_owned()), |
1992 | )); |
1993 | } |
1994 | let value = ok!(value.to_str().ok_or_else(|| { |
1995 | crate::Error::invalid_utf8( |
1996 | cmd, |
1997 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
1998 | ) |
1999 | })); |
2000 | Ok(value.to_owned()) |
2001 | } |
2002 | } |
2003 | |
2004 | impl Default for NonEmptyStringValueParser { |
2005 | fn default() -> Self { |
2006 | Self::new() |
2007 | } |
2008 | } |
2009 | |
2010 | /// Adapt a `TypedValueParser` from one value to another |
2011 | /// |
2012 | /// See [`TypedValueParser::map`] |
2013 | #[derive (Clone, Debug)] |
2014 | pub struct MapValueParser<P, F> { |
2015 | parser: P, |
2016 | func: F, |
2017 | } |
2018 | |
2019 | impl<P, F, T> MapValueParser<P, F> |
2020 | where |
2021 | P: TypedValueParser, |
2022 | P::Value: Send + Sync + Clone, |
2023 | F: Fn(P::Value) -> T + Clone, |
2024 | T: Send + Sync + Clone, |
2025 | { |
2026 | fn new(parser: P, func: F) -> Self { |
2027 | Self { parser, func } |
2028 | } |
2029 | } |
2030 | |
2031 | impl<P, F, T> TypedValueParser for MapValueParser<P, F> |
2032 | where |
2033 | P: TypedValueParser, |
2034 | P::Value: Send + Sync + Clone, |
2035 | F: Fn(P::Value) -> T + Clone + Send + Sync + 'static, |
2036 | T: Send + Sync + Clone, |
2037 | { |
2038 | type Value = T; |
2039 | |
2040 | fn parse_ref( |
2041 | &self, |
2042 | cmd: &crate::Command, |
2043 | arg: Option<&crate::Arg>, |
2044 | value: &std::ffi::OsStr, |
2045 | ) -> Result<Self::Value, crate::Error> { |
2046 | let value = ok!(self.parser.parse_ref(cmd, arg, value)); |
2047 | let value = (self.func)(value); |
2048 | Ok(value) |
2049 | } |
2050 | |
2051 | fn parse( |
2052 | &self, |
2053 | cmd: &crate::Command, |
2054 | arg: Option<&crate::Arg>, |
2055 | value: std::ffi::OsString, |
2056 | ) -> Result<Self::Value, crate::Error> { |
2057 | let value = ok!(self.parser.parse(cmd, arg, value)); |
2058 | let value = (self.func)(value); |
2059 | Ok(value) |
2060 | } |
2061 | |
2062 | fn possible_values( |
2063 | &self, |
2064 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
2065 | self.parser.possible_values() |
2066 | } |
2067 | } |
2068 | |
2069 | /// Adapt a `TypedValueParser` from one value to another |
2070 | /// |
2071 | /// See [`TypedValueParser::try_map`] |
2072 | #[derive (Clone, Debug)] |
2073 | pub struct TryMapValueParser<P, F> { |
2074 | parser: P, |
2075 | func: F, |
2076 | } |
2077 | |
2078 | impl<P, F, T, E> TryMapValueParser<P, F> |
2079 | where |
2080 | P: TypedValueParser, |
2081 | P::Value: Send + Sync + Clone, |
2082 | F: Fn(P::Value) -> Result<T, E> + Clone + Send + Sync + 'static, |
2083 | T: Send + Sync + Clone, |
2084 | E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
2085 | { |
2086 | fn new(parser: P, func: F) -> Self { |
2087 | Self { parser, func } |
2088 | } |
2089 | } |
2090 | |
2091 | impl<P, F, T, E> TypedValueParser for TryMapValueParser<P, F> |
2092 | where |
2093 | P: TypedValueParser, |
2094 | P::Value: Send + Sync + Clone, |
2095 | F: Fn(P::Value) -> Result<T, E> + Clone + Send + Sync + 'static, |
2096 | T: Send + Sync + Clone, |
2097 | E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
2098 | { |
2099 | type Value = T; |
2100 | |
2101 | fn parse_ref( |
2102 | &self, |
2103 | cmd: &crate::Command, |
2104 | arg: Option<&crate::Arg>, |
2105 | value: &std::ffi::OsStr, |
2106 | ) -> Result<Self::Value, crate::Error> { |
2107 | let mid_value = ok!(self.parser.parse_ref(cmd, arg, value)); |
2108 | let value = ok!((self.func)(mid_value).map_err(|e| { |
2109 | let arg = arg |
2110 | .map(|a| a.to_string()) |
2111 | .unwrap_or_else(|| "..." .to_owned()); |
2112 | crate::Error::value_validation(arg, value.to_string_lossy().into_owned(), e.into()) |
2113 | .with_cmd(cmd) |
2114 | })); |
2115 | Ok(value) |
2116 | } |
2117 | |
2118 | fn possible_values( |
2119 | &self, |
2120 | ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { |
2121 | self.parser.possible_values() |
2122 | } |
2123 | } |
2124 | |
2125 | /// When encountered, report [`ErrorKind::UnknownArgument`][crate::error::ErrorKind::UnknownArgument] |
2126 | /// |
2127 | /// Useful to help users migrate, either from old versions or similar tools. |
2128 | /// |
2129 | /// # Examples |
2130 | /// |
2131 | /// ```rust |
2132 | /// # use clap_builder as clap; |
2133 | /// # use clap::Command; |
2134 | /// # use clap::Arg; |
2135 | /// let cmd = Command::new("mycmd" ) |
2136 | /// .args([ |
2137 | /// Arg::new("current-dir" ) |
2138 | /// .short('C' ), |
2139 | /// Arg::new("current-dir-unknown" ) |
2140 | /// .long("cwd" ) |
2141 | /// .aliases(["current-dir" , "directory" , "working-directory" , "root" ]) |
2142 | /// .value_parser(clap::builder::UnknownArgumentValueParser::suggest_arg("-C" )) |
2143 | /// .hide(true), |
2144 | /// ]); |
2145 | /// |
2146 | /// // Use a supported version of the argument |
2147 | /// let matches = cmd.clone().try_get_matches_from(["mycmd" , "-C" , ".." ]).unwrap(); |
2148 | /// assert!(matches.contains_id("current-dir" )); |
2149 | /// assert_eq!( |
2150 | /// matches.get_many::<String>("current-dir" ).unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(), |
2151 | /// vec![".." ] |
2152 | /// ); |
2153 | /// |
2154 | /// // Use one of the invalid versions |
2155 | /// let err = cmd.try_get_matches_from(["mycmd" , "--cwd" , ".." ]).unwrap_err(); |
2156 | /// assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument); |
2157 | /// ``` |
2158 | #[derive (Clone, Debug)] |
2159 | pub struct UnknownArgumentValueParser { |
2160 | arg: Option<Str>, |
2161 | suggestions: Vec<StyledStr>, |
2162 | } |
2163 | |
2164 | impl UnknownArgumentValueParser { |
2165 | /// Suggest an alternative argument |
2166 | pub fn suggest_arg(arg: impl Into<Str>) -> Self { |
2167 | Self { |
2168 | arg: Some(arg.into()), |
2169 | suggestions: Default::default(), |
2170 | } |
2171 | } |
2172 | |
2173 | /// Provide a general suggestion |
2174 | pub fn suggest(text: impl Into<StyledStr>) -> Self { |
2175 | Self { |
2176 | arg: Default::default(), |
2177 | suggestions: vec![text.into()], |
2178 | } |
2179 | } |
2180 | |
2181 | /// Extend the suggestions |
2182 | pub fn and_suggest(mut self, text: impl Into<StyledStr>) -> Self { |
2183 | self.suggestions.push(text.into()); |
2184 | self |
2185 | } |
2186 | } |
2187 | |
2188 | impl TypedValueParser for UnknownArgumentValueParser { |
2189 | type Value = String; |
2190 | |
2191 | fn parse_ref( |
2192 | &self, |
2193 | cmd: &crate::Command, |
2194 | arg: Option<&crate::Arg>, |
2195 | value: &std::ffi::OsStr, |
2196 | ) -> Result<Self::Value, crate::Error> { |
2197 | TypedValueParser::parse_ref_(self, cmd, arg, value, ValueSource::CommandLine) |
2198 | } |
2199 | |
2200 | fn parse_ref_( |
2201 | &self, |
2202 | cmd: &crate::Command, |
2203 | arg: Option<&crate::Arg>, |
2204 | _value: &std::ffi::OsStr, |
2205 | source: ValueSource, |
2206 | ) -> Result<Self::Value, crate::Error> { |
2207 | match source { |
2208 | ValueSource::DefaultValue => { |
2209 | TypedValueParser::parse_ref_(&StringValueParser::new(), cmd, arg, _value, source) |
2210 | } |
2211 | ValueSource::EnvVariable | ValueSource::CommandLine => { |
2212 | let arg = match arg { |
2213 | Some(arg) => arg.to_string(), |
2214 | None => ".." .to_owned(), |
2215 | }; |
2216 | let err = crate::Error::unknown_argument( |
2217 | cmd, |
2218 | arg, |
2219 | self.arg.as_ref().map(|s| (s.as_str().to_owned(), None)), |
2220 | false, |
2221 | crate::output::Usage::new(cmd).create_usage_with_title(&[]), |
2222 | ); |
2223 | #[cfg (feature = "error-context" )] |
2224 | let err = { |
2225 | debug_assert_eq!( |
2226 | err.get(crate::error::ContextKind::Suggested), |
2227 | None, |
2228 | "Assuming `Error::unknown_argument` doesn't apply any `Suggested` so we can without caution" |
2229 | ); |
2230 | err.insert_context_unchecked( |
2231 | crate::error::ContextKind::Suggested, |
2232 | crate::error::ContextValue::StyledStrs(self.suggestions.clone()), |
2233 | ) |
2234 | }; |
2235 | Err(err) |
2236 | } |
2237 | } |
2238 | } |
2239 | } |
2240 | |
2241 | /// Register a type with [`value_parser!`][crate::value_parser!] |
2242 | /// |
2243 | /// # Example |
2244 | /// |
2245 | /// ```rust |
2246 | /// # use clap_builder as clap; |
2247 | /// #[derive(Copy, Clone, Debug)] |
2248 | /// pub struct Custom(u32); |
2249 | /// |
2250 | /// impl clap::builder::ValueParserFactory for Custom { |
2251 | /// type Parser = CustomValueParser; |
2252 | /// fn value_parser() -> Self::Parser { |
2253 | /// CustomValueParser |
2254 | /// } |
2255 | /// } |
2256 | /// |
2257 | /// #[derive(Clone, Debug)] |
2258 | /// pub struct CustomValueParser; |
2259 | /// impl clap::builder::TypedValueParser for CustomValueParser { |
2260 | /// type Value = Custom; |
2261 | /// |
2262 | /// fn parse_ref( |
2263 | /// &self, |
2264 | /// cmd: &clap::Command, |
2265 | /// arg: Option<&clap::Arg>, |
2266 | /// value: &std::ffi::OsStr, |
2267 | /// ) -> Result<Self::Value, clap::Error> { |
2268 | /// let inner = clap::value_parser!(u32); |
2269 | /// let val = inner.parse_ref(cmd, arg, value)?; |
2270 | /// Ok(Custom(val)) |
2271 | /// } |
2272 | /// } |
2273 | /// |
2274 | /// let parser: CustomValueParser = clap::value_parser!(Custom); |
2275 | /// ``` |
2276 | pub trait ValueParserFactory { |
2277 | /// Generated parser, usually [`ValueParser`]. |
2278 | /// |
2279 | /// It should at least be a type that supports `Into<ValueParser>`. A non-`ValueParser` type |
2280 | /// allows the caller to do further initialization on the parser. |
2281 | type Parser; |
2282 | |
2283 | /// Create the specified [`Self::Parser`] |
2284 | fn value_parser() -> Self::Parser; |
2285 | } |
2286 | impl ValueParserFactory for String { |
2287 | type Parser = ValueParser; |
2288 | fn value_parser() -> Self::Parser { |
2289 | ValueParser::string() // Default `clap_derive` to optimized implementation |
2290 | } |
2291 | } |
2292 | impl ValueParserFactory for Box<str> { |
2293 | type Parser = MapValueParser<StringValueParser, fn(String) -> Box<str>>; |
2294 | fn value_parser() -> Self::Parser { |
2295 | StringValueParser::new().map(func:String::into_boxed_str) |
2296 | } |
2297 | } |
2298 | impl ValueParserFactory for std::ffi::OsString { |
2299 | type Parser = ValueParser; |
2300 | fn value_parser() -> Self::Parser { |
2301 | ValueParser::os_string() // Default `clap_derive` to optimized implementation |
2302 | } |
2303 | } |
2304 | impl ValueParserFactory for Box<std::ffi::OsStr> { |
2305 | type Parser = |
2306 | MapValueParser<OsStringValueParser, fn(std::ffi::OsString) -> Box<std::ffi::OsStr>>; |
2307 | fn value_parser() -> Self::Parser { |
2308 | OsStringValueParser::new().map(func:std::ffi::OsString::into_boxed_os_str) |
2309 | } |
2310 | } |
2311 | impl ValueParserFactory for std::path::PathBuf { |
2312 | type Parser = ValueParser; |
2313 | fn value_parser() -> Self::Parser { |
2314 | ValueParser::path_buf() // Default `clap_derive` to optimized implementation |
2315 | } |
2316 | } |
2317 | impl ValueParserFactory for Box<std::path::Path> { |
2318 | type Parser = |
2319 | MapValueParser<PathBufValueParser, fn(std::path::PathBuf) -> Box<std::path::Path>>; |
2320 | fn value_parser() -> Self::Parser { |
2321 | PathBufValueParser::new().map(func:std::path::PathBuf::into_boxed_path) |
2322 | } |
2323 | } |
2324 | impl ValueParserFactory for bool { |
2325 | type Parser = ValueParser; |
2326 | fn value_parser() -> Self::Parser { |
2327 | ValueParser::bool() // Default `clap_derive` to optimized implementation |
2328 | } |
2329 | } |
2330 | impl ValueParserFactory for u8 { |
2331 | type Parser = RangedI64ValueParser<u8>; |
2332 | fn value_parser() -> Self::Parser { |
2333 | let start: i64 = u8::MIN.into(); |
2334 | let end: i64 = u8::MAX.into(); |
2335 | RangedI64ValueParser::new().range(start..=end) |
2336 | } |
2337 | } |
2338 | impl ValueParserFactory for i8 { |
2339 | type Parser = RangedI64ValueParser<i8>; |
2340 | fn value_parser() -> Self::Parser { |
2341 | let start: i64 = i8::MIN.into(); |
2342 | let end: i64 = i8::MAX.into(); |
2343 | RangedI64ValueParser::new().range(start..=end) |
2344 | } |
2345 | } |
2346 | impl ValueParserFactory for u16 { |
2347 | type Parser = RangedI64ValueParser<u16>; |
2348 | fn value_parser() -> Self::Parser { |
2349 | let start: i64 = u16::MIN.into(); |
2350 | let end: i64 = u16::MAX.into(); |
2351 | RangedI64ValueParser::new().range(start..=end) |
2352 | } |
2353 | } |
2354 | impl ValueParserFactory for i16 { |
2355 | type Parser = RangedI64ValueParser<i16>; |
2356 | fn value_parser() -> Self::Parser { |
2357 | let start: i64 = i16::MIN.into(); |
2358 | let end: i64 = i16::MAX.into(); |
2359 | RangedI64ValueParser::new().range(start..=end) |
2360 | } |
2361 | } |
2362 | impl ValueParserFactory for u32 { |
2363 | type Parser = RangedI64ValueParser<u32>; |
2364 | fn value_parser() -> Self::Parser { |
2365 | let start: i64 = u32::MIN.into(); |
2366 | let end: i64 = u32::MAX.into(); |
2367 | RangedI64ValueParser::new().range(start..=end) |
2368 | } |
2369 | } |
2370 | impl ValueParserFactory for i32 { |
2371 | type Parser = RangedI64ValueParser<i32>; |
2372 | fn value_parser() -> Self::Parser { |
2373 | let start: i64 = i32::MIN.into(); |
2374 | let end: i64 = i32::MAX.into(); |
2375 | RangedI64ValueParser::new().range(start..=end) |
2376 | } |
2377 | } |
2378 | impl ValueParserFactory for u64 { |
2379 | type Parser = RangedU64ValueParser<u64>; |
2380 | fn value_parser() -> Self::Parser { |
2381 | RangedU64ValueParser::new() |
2382 | } |
2383 | } |
2384 | impl ValueParserFactory for i64 { |
2385 | type Parser = RangedI64ValueParser<i64>; |
2386 | fn value_parser() -> Self::Parser { |
2387 | RangedI64ValueParser::new() |
2388 | } |
2389 | } |
2390 | impl<T> ValueParserFactory for std::num::Saturating<T> |
2391 | where |
2392 | T: ValueParserFactory, |
2393 | <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, |
2394 | T: Send + Sync + Clone, |
2395 | { |
2396 | type Parser = |
2397 | MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> std::num::Saturating<T>>; |
2398 | fn value_parser() -> Self::Parser { |
2399 | T::value_parser().map(func:std::num::Saturating) |
2400 | } |
2401 | } |
2402 | impl<T> ValueParserFactory for std::num::Wrapping<T> |
2403 | where |
2404 | T: ValueParserFactory, |
2405 | <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, |
2406 | T: Send + Sync + Clone, |
2407 | { |
2408 | type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> std::num::Wrapping<T>>; |
2409 | fn value_parser() -> Self::Parser { |
2410 | T::value_parser().map(func:std::num::Wrapping) |
2411 | } |
2412 | } |
2413 | impl<T> ValueParserFactory for Box<T> |
2414 | where |
2415 | T: ValueParserFactory, |
2416 | <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, |
2417 | T: Send + Sync + Clone, |
2418 | { |
2419 | type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> Box<T>>; |
2420 | fn value_parser() -> Self::Parser { |
2421 | T::value_parser().map(func:Box::new) |
2422 | } |
2423 | } |
2424 | impl<T> ValueParserFactory for std::sync::Arc<T> |
2425 | where |
2426 | T: ValueParserFactory, |
2427 | <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, |
2428 | T: Send + Sync + Clone, |
2429 | { |
2430 | type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> std::sync::Arc<T>>; |
2431 | fn value_parser() -> Self::Parser { |
2432 | T::value_parser().map(func:std::sync::Arc::new) |
2433 | } |
2434 | } |
2435 | |
2436 | #[doc (hidden)] |
2437 | #[derive (Debug)] |
2438 | #[allow (non_camel_case_types)] |
2439 | pub struct _infer_ValueParser_for<T>(std::marker::PhantomData<T>); |
2440 | |
2441 | impl<T> _infer_ValueParser_for<T> { |
2442 | #[doc (hidden)] |
2443 | #[allow (clippy::new_without_default)] |
2444 | pub fn new() -> Self { |
2445 | Self(Default::default()) |
2446 | } |
2447 | } |
2448 | |
2449 | /// Unstable [`ValueParser`] |
2450 | /// |
2451 | /// Implementation may change to more specific instance in the future |
2452 | #[doc (hidden)] |
2453 | #[derive (Debug)] |
2454 | pub struct _AnonymousValueParser(ValueParser); |
2455 | |
2456 | #[doc (hidden)] |
2457 | pub mod impl_prelude { |
2458 | use super::*; |
2459 | |
2460 | #[doc (hidden)] |
2461 | #[allow (non_camel_case_types)] |
2462 | pub trait _impls_ValueParserFactory: private::_impls_ValueParserFactorySealed { |
2463 | type Parser; |
2464 | fn value_parser(&self) -> Self::Parser; |
2465 | } |
2466 | impl<P: ValueParserFactory> _impls_ValueParserFactory for &&&&&&_infer_ValueParser_for<P> { |
2467 | type Parser = P::Parser; |
2468 | fn value_parser(&self) -> Self::Parser { |
2469 | P::value_parser() |
2470 | } |
2471 | } |
2472 | |
2473 | #[doc (hidden)] |
2474 | #[allow (non_camel_case_types)] |
2475 | pub trait _impls_ValueEnum: private::_impls_ValueEnumSealed { |
2476 | type Output; |
2477 | |
2478 | fn value_parser(&self) -> Self::Output; |
2479 | } |
2480 | impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> _impls_ValueEnum |
2481 | for &&&&&_infer_ValueParser_for<E> |
2482 | { |
2483 | type Output = EnumValueParser<E>; |
2484 | |
2485 | fn value_parser(&self) -> Self::Output { |
2486 | EnumValueParser::<E>::new() |
2487 | } |
2488 | } |
2489 | |
2490 | #[doc (hidden)] |
2491 | #[allow (non_camel_case_types)] |
2492 | pub trait _impls_From_OsString: private::_impls_From_OsStringSealed { |
2493 | fn value_parser(&self) -> _AnonymousValueParser; |
2494 | } |
2495 | impl<FromOsString> _impls_From_OsString for &&&&_infer_ValueParser_for<FromOsString> |
2496 | where |
2497 | FromOsString: From<std::ffi::OsString> + std::any::Any + Clone + Send + Sync + 'static, |
2498 | { |
2499 | fn value_parser(&self) -> _AnonymousValueParser { |
2500 | _AnonymousValueParser( |
2501 | OsStringValueParser::new() |
2502 | .map(|s| FromOsString::from(s)) |
2503 | .into(), |
2504 | ) |
2505 | } |
2506 | } |
2507 | |
2508 | #[doc (hidden)] |
2509 | #[allow (non_camel_case_types)] |
2510 | pub trait _impls_From_OsStr: private::_impls_From_OsStrSealed { |
2511 | fn value_parser(&self) -> _AnonymousValueParser; |
2512 | } |
2513 | impl<FromOsStr> _impls_From_OsStr for &&&_infer_ValueParser_for<FromOsStr> |
2514 | where |
2515 | FromOsStr: |
2516 | for<'s> From<&'s std::ffi::OsStr> + std::any::Any + Clone + Send + Sync + 'static, |
2517 | { |
2518 | fn value_parser(&self) -> _AnonymousValueParser { |
2519 | _AnonymousValueParser( |
2520 | OsStringValueParser::new() |
2521 | .map(|s| FromOsStr::from(&s)) |
2522 | .into(), |
2523 | ) |
2524 | } |
2525 | } |
2526 | |
2527 | #[doc (hidden)] |
2528 | #[allow (non_camel_case_types)] |
2529 | pub trait _impls_From_String: private::_impls_From_StringSealed { |
2530 | fn value_parser(&self) -> _AnonymousValueParser; |
2531 | } |
2532 | impl<FromString> _impls_From_String for &&_infer_ValueParser_for<FromString> |
2533 | where |
2534 | FromString: From<String> + std::any::Any + Clone + Send + Sync + 'static, |
2535 | { |
2536 | fn value_parser(&self) -> _AnonymousValueParser { |
2537 | _AnonymousValueParser(StringValueParser::new().map(|s| FromString::from(s)).into()) |
2538 | } |
2539 | } |
2540 | |
2541 | #[doc (hidden)] |
2542 | #[allow (non_camel_case_types)] |
2543 | pub trait _impls_From_str: private::_impls_From_strSealed { |
2544 | fn value_parser(&self) -> _AnonymousValueParser; |
2545 | } |
2546 | impl<FromStr> _impls_From_str for &_infer_ValueParser_for<FromStr> |
2547 | where |
2548 | FromStr: for<'s> From<&'s str> + std::any::Any + Clone + Send + Sync + 'static, |
2549 | { |
2550 | fn value_parser(&self) -> _AnonymousValueParser { |
2551 | _AnonymousValueParser(StringValueParser::new().map(|s| FromStr::from(&s)).into()) |
2552 | } |
2553 | } |
2554 | |
2555 | #[doc (hidden)] |
2556 | #[allow (non_camel_case_types)] |
2557 | pub trait _impls_FromStr: private::_impls_FromStrSealed { |
2558 | fn value_parser(&self) -> _AnonymousValueParser; |
2559 | } |
2560 | impl<Parse> _impls_FromStr for _infer_ValueParser_for<Parse> |
2561 | where |
2562 | Parse: std::str::FromStr + std::any::Any + Clone + Send + Sync + 'static, |
2563 | <Parse as std::str::FromStr>::Err: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
2564 | { |
2565 | fn value_parser(&self) -> _AnonymousValueParser { |
2566 | let func: fn(&str) -> Result<Parse, <Parse as std::str::FromStr>::Err> = |
2567 | Parse::from_str; |
2568 | _AnonymousValueParser(ValueParser::new(func)) |
2569 | } |
2570 | } |
2571 | } |
2572 | |
2573 | /// Select a [`ValueParser`] implementation from the intended type |
2574 | /// |
2575 | /// Supported types |
2576 | /// - [`ValueParserFactory` types][ValueParserFactory], including |
2577 | /// - [Native types][ValueParser]: `bool`, `String`, `OsString`, `PathBuf` |
2578 | /// - [Ranged numeric types][RangedI64ValueParser]: `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64` |
2579 | /// - [`ValueEnum` types][crate::ValueEnum] |
2580 | /// - [`From<OsString>` types][std::convert::From] and [`From<&OsStr>` types][std::convert::From] |
2581 | /// - [`From<String>` types][std::convert::From] and [`From<&str>` types][std::convert::From] |
2582 | /// - [`FromStr` types][std::str::FromStr], including usize, isize |
2583 | /// |
2584 | /// # Example |
2585 | /// |
2586 | /// Usage: |
2587 | /// ```rust |
2588 | /// # use clap_builder as clap; |
2589 | /// # use std::path::PathBuf; |
2590 | /// # use std::path::Path; |
2591 | /// let mut cmd = clap::Command::new("raw" ) |
2592 | /// .arg( |
2593 | /// clap::Arg::new("output" ) |
2594 | /// .value_parser(clap::value_parser!(PathBuf)) |
2595 | /// .required(true) |
2596 | /// ); |
2597 | /// |
2598 | /// let m = cmd.try_get_matches_from_mut(["cmd" , "file.txt" ]).unwrap(); |
2599 | /// let port: &PathBuf = m.get_one("output" ) |
2600 | /// .expect("required" ); |
2601 | /// assert_eq!(port, Path::new("file.txt" )); |
2602 | /// ``` |
2603 | /// |
2604 | /// Example mappings: |
2605 | /// ```rust |
2606 | /// # use clap_builder as clap; |
2607 | /// # use clap::ColorChoice; |
2608 | /// // Built-in types |
2609 | /// let parser = clap::value_parser!(String); |
2610 | /// assert_eq!(format!("{parser:?}" ), "ValueParser::string" ); |
2611 | /// let parser = clap::value_parser!(std::ffi::OsString); |
2612 | /// assert_eq!(format!("{parser:?}" ), "ValueParser::os_string" ); |
2613 | /// let parser = clap::value_parser!(std::path::PathBuf); |
2614 | /// assert_eq!(format!("{parser:?}" ), "ValueParser::path_buf" ); |
2615 | /// clap::value_parser!(u16).range(3000..); |
2616 | /// clap::value_parser!(u64).range(3000..); |
2617 | /// |
2618 | /// // FromStr types |
2619 | /// let parser = clap::value_parser!(usize); |
2620 | /// assert_eq!(format!("{parser:?}" ), "_AnonymousValueParser(ValueParser::other(usize))" ); |
2621 | /// |
2622 | /// // ValueEnum types |
2623 | /// clap::value_parser!(ColorChoice); |
2624 | /// ``` |
2625 | #[macro_export ] |
2626 | macro_rules! value_parser { |
2627 | ($name:ty) => {{ |
2628 | use $crate::builder::impl_prelude::*; |
2629 | let auto = $crate::builder::_infer_ValueParser_for::<$name>::new(); |
2630 | (&&&&&&auto).value_parser() |
2631 | }}; |
2632 | } |
2633 | |
2634 | mod private { |
2635 | use super::*; |
2636 | |
2637 | #[allow (non_camel_case_types)] |
2638 | pub trait _impls_ValueParserFactorySealed {} |
2639 | impl<P: ValueParserFactory> _impls_ValueParserFactorySealed for &&&&&&_infer_ValueParser_for<P> {} |
2640 | |
2641 | #[allow (non_camel_case_types)] |
2642 | pub trait _impls_ValueEnumSealed {} |
2643 | impl<E: crate::ValueEnum> _impls_ValueEnumSealed for &&&&&_infer_ValueParser_for<E> {} |
2644 | |
2645 | #[allow (non_camel_case_types)] |
2646 | pub trait _impls_From_OsStringSealed {} |
2647 | impl<FromOsString> _impls_From_OsStringSealed for &&&&_infer_ValueParser_for<FromOsString> where |
2648 | FromOsString: From<std::ffi::OsString> + std::any::Any + Send + Sync + 'static |
2649 | { |
2650 | } |
2651 | |
2652 | #[allow (non_camel_case_types)] |
2653 | pub trait _impls_From_OsStrSealed {} |
2654 | impl<FromOsStr> _impls_From_OsStrSealed for &&&_infer_ValueParser_for<FromOsStr> where |
2655 | FromOsStr: for<'s> From<&'s std::ffi::OsStr> + std::any::Any + Send + Sync + 'static |
2656 | { |
2657 | } |
2658 | |
2659 | #[allow (non_camel_case_types)] |
2660 | pub trait _impls_From_StringSealed {} |
2661 | impl<FromString> _impls_From_StringSealed for &&_infer_ValueParser_for<FromString> where |
2662 | FromString: From<String> + std::any::Any + Send + Sync + 'static |
2663 | { |
2664 | } |
2665 | |
2666 | #[allow (non_camel_case_types)] |
2667 | pub trait _impls_From_strSealed {} |
2668 | impl<FromStr> _impls_From_strSealed for &_infer_ValueParser_for<FromStr> where |
2669 | FromStr: for<'s> From<&'s str> + std::any::Any + Send + Sync + 'static |
2670 | { |
2671 | } |
2672 | |
2673 | #[allow (non_camel_case_types)] |
2674 | pub trait _impls_FromStrSealed {} |
2675 | impl<Parse> _impls_FromStrSealed for _infer_ValueParser_for<Parse> |
2676 | where |
2677 | Parse: std::str::FromStr + std::any::Any + Send + Sync + 'static, |
2678 | <Parse as std::str::FromStr>::Err: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, |
2679 | { |
2680 | } |
2681 | } |
2682 | |
2683 | #[cfg (test)] |
2684 | mod test { |
2685 | use super::*; |
2686 | |
2687 | #[test ] |
2688 | fn ensure_typed_applies_to_parse() { |
2689 | fn parse(_: &str) -> Result<usize, std::io::Error> { |
2690 | Ok(10) |
2691 | } |
2692 | let cmd = crate::Command::new("cmd" ); |
2693 | let arg = None; |
2694 | assert_eq!( |
2695 | TypedValueParser::parse_ref(&parse, &cmd, arg, std::ffi::OsStr::new("foo" )).unwrap(), |
2696 | 10 |
2697 | ); |
2698 | } |
2699 | } |
2700 | |