clap_builder/builder/value_parser.rs
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::<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::<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::<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::<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::<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::<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::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::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("ValueParser::bool").finish(),
570 ValueParserInner::String => f.debug_struct("ValueParser::string").finish(),
571 ValueParserInner::OsString => f.debug_struct("ValueParser::os_string").finish(),
572 ValueParserInner::PathBuf => f.debug_struct("ValueParser::path_buf").finish(),
573 ValueParserInner::Other(o) => write!(f, "ValueParser::other({:?})", o.type_id()),
574 }
575 }
576}
577
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) => 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 /// 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
619impl<T, P> AnyValueParser for P
620where
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/// ```
711pub 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
870impl<F, T, E> TypedValueParser for F
871where
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 = 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 = 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]
905pub struct StringValueParser {}
906
907impl StringValueParser {
908 /// Implementation for [`ValueParser::string`]
909 pub fn new() -> Self {
910 Self {}
911 }
912}
913
914impl 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
942impl 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]
953pub struct OsStringValueParser {}
954
955impl OsStringValueParser {
956 /// Implementation for [`ValueParser::os_string`]
957 pub fn new() -> Self {
958 Self {}
959 }
960}
961
962impl 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
984impl 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]
995pub struct PathBufValueParser {}
996
997impl PathBufValueParser {
998 /// Implementation for [`ValueParser::path_buf`]
999 pub fn new() -> Self {
1000 Self {}
1001 }
1002}
1003
1004impl 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
1034impl 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)]
1079pub struct EnumValueParser<E: crate::ValueEnum + Clone + Send + Sync + 'static>(
1080 std::marker::PhantomData<E>,
1081);
1082
1083impl<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
1091impl<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
1150impl<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)]
1196pub struct PossibleValuesParser(Vec<super::PossibleValue>);
1197
1198impl 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
1205impl 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
1258impl<I, T> From<I> for PossibleValuesParser
1259where
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.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)]
1315pub 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
1320impl<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
1400impl<T: TryFrom<i64> + Clone + Send + Sync + 'static> TypedValueParser for RangedI64ValueParser<T>
1401where
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
1458impl<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
1469impl<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)]
1514pub struct RangedU64ValueParser<T: TryFrom<u64> = u64> {
1515 bounds: (std::ops::Bound<u64>, std::ops::Bound<u64>),
1516 target: std::marker::PhantomData<T>,
1517}
1518
1519impl<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
1599impl<T: TryFrom<u64> + Clone + Send + Sync + 'static> TypedValueParser for RangedU64ValueParser<T>
1600where
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
1657impl<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
1666impl<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]
1677pub struct BoolValueParser {}
1678
1679impl 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
1693impl 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
1730impl 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]
1778pub struct FalseyValueParser {}
1779
1780impl 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 crate::util::TRUE_LITERALS
1788 .iter()
1789 .chain(crate::util::FALSE_LITERALS.iter())
1790 .copied()
1791 .map(|l| crate::builder::PossibleValue::new(l).hide(l != "true" && l != "false"))
1792 }
1793}
1794
1795impl 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
1825impl 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]
1877pub struct BoolishValueParser {}
1878
1879impl 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 crate::util::TRUE_LITERALS
1887 .iter()
1888 .chain(crate::util::FALSE_LITERALS.iter())
1889 .copied()
1890 .map(|l| crate::builder::PossibleValue::new(l).hide(l != "true" && l != "false"))
1891 }
1892}
1893
1894impl 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
1926impl 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]
1968pub struct NonEmptyStringValueParser {}
1969
1970impl NonEmptyStringValueParser {
1971 /// Parse non-empty string values
1972 pub fn new() -> Self {
1973 Self {}
1974 }
1975}
1976
1977impl 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
2004impl 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)]
2014pub struct MapValueParser<P, F> {
2015 parser: P,
2016 func: F,
2017}
2018
2019impl<P, F, T> MapValueParser<P, F>
2020where
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
2031impl<P, F, T> TypedValueParser for MapValueParser<P, F>
2032where
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)]
2073pub struct TryMapValueParser<P, F> {
2074 parser: P,
2075 func: F,
2076}
2077
2078impl<P, F, T, E> TryMapValueParser<P, F>
2079where
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
2091impl<P, F, T, E> TypedValueParser for TryMapValueParser<P, F>
2092where
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)]
2159pub struct UnknownArgumentValueParser {
2160 arg: Option<Str>,
2161 suggestions: Vec<StyledStr>,
2162}
2163
2164impl 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
2188impl 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/// ```
2276pub 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}
2286impl ValueParserFactory for String {
2287 type Parser = ValueParser;
2288 fn value_parser() -> Self::Parser {
2289 ValueParser::string() // Default `clap_derive` to optimized implementation
2290 }
2291}
2292impl ValueParserFactory for Box<str> {
2293 type Parser = MapValueParser<StringValueParser, fn(String) -> Box<str>>;
2294 fn value_parser() -> Self::Parser {
2295 StringValueParser::new().map(String::into_boxed_str)
2296 }
2297}
2298impl 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}
2304impl 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(std::ffi::OsString::into_boxed_os_str)
2309 }
2310}
2311impl 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}
2317impl 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(std::path::PathBuf::into_boxed_path)
2322 }
2323}
2324impl ValueParserFactory for bool {
2325 type Parser = ValueParser;
2326 fn value_parser() -> Self::Parser {
2327 ValueParser::bool() // Default `clap_derive` to optimized implementation
2328 }
2329}
2330impl 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}
2338impl 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}
2346impl 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}
2354impl 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}
2362impl 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}
2370impl 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}
2378impl ValueParserFactory for u64 {
2379 type Parser = RangedU64ValueParser<u64>;
2380 fn value_parser() -> Self::Parser {
2381 RangedU64ValueParser::new()
2382 }
2383}
2384impl ValueParserFactory for i64 {
2385 type Parser = RangedI64ValueParser<i64>;
2386 fn value_parser() -> Self::Parser {
2387 RangedI64ValueParser::new()
2388 }
2389}
2390impl<T> ValueParserFactory for std::num::Saturating<T>
2391where
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(std::num::Saturating)
2400 }
2401}
2402impl<T> ValueParserFactory for std::num::Wrapping<T>
2403where
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(std::num::Wrapping)
2411 }
2412}
2413impl<T> ValueParserFactory for Box<T>
2414where
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(Box::new)
2422 }
2423}
2424impl<T> ValueParserFactory for std::sync::Arc<T>
2425where
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(std::sync::Arc::new)
2433 }
2434}
2435
2436#[doc(hidden)]
2437#[derive(Debug)]
2438#[allow(non_camel_case_types)]
2439pub struct _infer_ValueParser_for<T>(std::marker::PhantomData<T>);
2440
2441impl<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)]
2454pub struct _AnonymousValueParser(ValueParser);
2455
2456#[doc(hidden)]
2457pub 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]
2626macro_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
2634mod 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)]
2684mod 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}