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