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/// **NOTE:** To capture negative values, you will also need to set
1271/// [`Arg::allow_negative_numbers`][crate::Arg::allow_negative_numbers] or
1272/// [`Arg::allow_hyphen_values`][crate::Arg::allow_hyphen_values].
1273///
1274/// # Example
1275///
1276/// Usage:
1277/// ```rust
1278/// # use clap_builder as clap;
1279/// let mut cmd = clap::Command::new("raw")
1280/// .arg(
1281/// clap::Arg::new("port")
1282/// .long("port")
1283/// .value_parser(clap::value_parser!(u16).range(3000..))
1284/// .action(clap::ArgAction::Set)
1285/// .required(true)
1286/// );
1287///
1288/// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "3001"]).unwrap();
1289/// let port: u16 = *m.get_one("port")
1290/// .expect("required");
1291/// assert_eq!(port, 3001);
1292/// ```
1293///
1294/// Semantics:
1295/// ```rust
1296/// # use clap_builder as clap;
1297/// # use std::ffi::OsStr;
1298/// # use clap::builder::TypedValueParser;
1299/// # let cmd = clap::Command::new("test");
1300/// # let arg = None;
1301/// let value_parser = clap::builder::RangedI64ValueParser::<i32>::new().range(-1..200);
1302/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).is_err());
1303/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err());
1304/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-200")).is_err());
1305/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("300")).is_err());
1306/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("-1")).unwrap(), -1);
1307/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0")).unwrap(), 0);
1308/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50")).unwrap(), 50);
1309/// ```
1310#[derive(Copy, Clone, Debug)]
1311pub struct RangedI64ValueParser<T: TryFrom<i64> + Clone + Send + Sync = i64> {
1312 bounds: (std::ops::Bound<i64>, std::ops::Bound<i64>),
1313 target: std::marker::PhantomData<T>,
1314}
1315
1316impl<T: TryFrom<i64> + Clone + Send + Sync> RangedI64ValueParser<T> {
1317 /// Select full range of `i64`
1318 pub fn new() -> Self {
1319 Self::from(..)
1320 }
1321
1322 /// Narrow the supported range
1323 pub fn range<B: RangeBounds<i64>>(mut self, range: B) -> Self {
1324 // Consideration: when the user does `value_parser!(u8).range()`
1325 // - Avoid programming mistakes by accidentally expanding the range
1326 // - Make it convenient to limit the range like with `..10`
1327 let start = match range.start_bound() {
1328 l @ std::ops::Bound::Included(i) => {
1329 debug_assert!(
1330 self.bounds.contains(i),
1331 "{} must be in {:?}",
1332 i,
1333 self.bounds
1334 );
1335 l.cloned()
1336 }
1337 l @ std::ops::Bound::Excluded(i) => {
1338 debug_assert!(
1339 self.bounds.contains(&i.saturating_add(1)),
1340 "{} must be in {:?}",
1341 i,
1342 self.bounds
1343 );
1344 l.cloned()
1345 }
1346 std::ops::Bound::Unbounded => self.bounds.start_bound().cloned(),
1347 };
1348 let end = match range.end_bound() {
1349 l @ std::ops::Bound::Included(i) => {
1350 debug_assert!(
1351 self.bounds.contains(i),
1352 "{} must be in {:?}",
1353 i,
1354 self.bounds
1355 );
1356 l.cloned()
1357 }
1358 l @ std::ops::Bound::Excluded(i) => {
1359 debug_assert!(
1360 self.bounds.contains(&i.saturating_sub(1)),
1361 "{} must be in {:?}",
1362 i,
1363 self.bounds
1364 );
1365 l.cloned()
1366 }
1367 std::ops::Bound::Unbounded => self.bounds.end_bound().cloned(),
1368 };
1369 self.bounds = (start, end);
1370 self
1371 }
1372
1373 fn format_bounds(&self) -> String {
1374 let mut result = match self.bounds.0 {
1375 std::ops::Bound::Included(i) => i.to_string(),
1376 std::ops::Bound::Excluded(i) => i.saturating_add(1).to_string(),
1377 std::ops::Bound::Unbounded => i64::MIN.to_string(),
1378 };
1379 result.push_str("..");
1380 match self.bounds.1 {
1381 std::ops::Bound::Included(i) => {
1382 result.push('=');
1383 result.push_str(&i.to_string());
1384 }
1385 std::ops::Bound::Excluded(i) => {
1386 result.push_str(&i.to_string());
1387 }
1388 std::ops::Bound::Unbounded => {
1389 result.push_str(&i64::MAX.to_string());
1390 }
1391 }
1392 result
1393 }
1394}
1395
1396impl<T: TryFrom<i64> + Clone + Send + Sync + 'static> TypedValueParser for RangedI64ValueParser<T>
1397where
1398 <T as TryFrom<i64>>::Error: Send + Sync + 'static + std::error::Error + ToString,
1399{
1400 type Value = T;
1401
1402 fn parse_ref(
1403 &self,
1404 cmd: &crate::Command,
1405 arg: Option<&crate::Arg>,
1406 raw_value: &std::ffi::OsStr,
1407 ) -> Result<Self::Value, crate::Error> {
1408 let value = ok!(raw_value.to_str().ok_or_else(|| {
1409 crate::Error::invalid_utf8(
1410 cmd,
1411 crate::output::Usage::new(cmd).create_usage_with_title(&[]),
1412 )
1413 }));
1414 let value = ok!(value.parse::<i64>().map_err(|err| {
1415 let arg = arg
1416 .map(|a| a.to_string())
1417 .unwrap_or_else(|| "...".to_owned());
1418 crate::Error::value_validation(
1419 arg,
1420 raw_value.to_string_lossy().into_owned(),
1421 err.into(),
1422 )
1423 .with_cmd(cmd)
1424 }));
1425 if !self.bounds.contains(&value) {
1426 let arg = arg
1427 .map(|a| a.to_string())
1428 .unwrap_or_else(|| "...".to_owned());
1429 return Err(crate::Error::value_validation(
1430 arg,
1431 raw_value.to_string_lossy().into_owned(),
1432 format!("{} is not in {}", value, self.format_bounds()).into(),
1433 )
1434 .with_cmd(cmd));
1435 }
1436
1437 let value: Result<Self::Value, _> = value.try_into();
1438 let value = ok!(value.map_err(|err| {
1439 let arg = arg
1440 .map(|a| a.to_string())
1441 .unwrap_or_else(|| "...".to_owned());
1442 crate::Error::value_validation(
1443 arg,
1444 raw_value.to_string_lossy().into_owned(),
1445 err.into(),
1446 )
1447 .with_cmd(cmd)
1448 }));
1449
1450 Ok(value)
1451 }
1452}
1453
1454impl<T: TryFrom<i64> + Clone + Send + Sync, B: RangeBounds<i64>> From<B>
1455 for RangedI64ValueParser<T>
1456{
1457 fn from(range: B) -> Self {
1458 Self {
1459 bounds: (range.start_bound().cloned(), range.end_bound().cloned()),
1460 target: Default::default(),
1461 }
1462 }
1463}
1464
1465impl<T: TryFrom<i64> + Clone + Send + Sync> Default for RangedI64ValueParser<T> {
1466 fn default() -> Self {
1467 Self::new()
1468 }
1469}
1470
1471/// Parse number that fall within a range of values
1472///
1473/// # Example
1474///
1475/// Usage:
1476/// ```rust
1477/// # use clap_builder as clap;
1478/// let mut cmd = clap::Command::new("raw")
1479/// .arg(
1480/// clap::Arg::new("port")
1481/// .long("port")
1482/// .value_parser(clap::value_parser!(u64).range(3000..))
1483/// .action(clap::ArgAction::Set)
1484/// .required(true)
1485/// );
1486///
1487/// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "3001"]).unwrap();
1488/// let port: u64 = *m.get_one("port")
1489/// .expect("required");
1490/// assert_eq!(port, 3001);
1491/// ```
1492///
1493/// Semantics:
1494/// ```rust
1495/// # use clap_builder as clap;
1496/// # use std::ffi::OsStr;
1497/// # use clap::builder::TypedValueParser;
1498/// # let cmd = clap::Command::new("test");
1499/// # let arg = None;
1500/// let value_parser = clap::builder::RangedU64ValueParser::<u32>::new().range(0..200);
1501/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).is_err());
1502/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err());
1503/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-200")).is_err());
1504/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("300")).is_err());
1505/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-1")).is_err());
1506/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0")).unwrap(), 0);
1507/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50")).unwrap(), 50);
1508/// ```
1509#[derive(Copy, Clone, Debug)]
1510pub struct RangedU64ValueParser<T: TryFrom<u64> = u64> {
1511 bounds: (std::ops::Bound<u64>, std::ops::Bound<u64>),
1512 target: std::marker::PhantomData<T>,
1513}
1514
1515impl<T: TryFrom<u64>> RangedU64ValueParser<T> {
1516 /// Select full range of `u64`
1517 pub fn new() -> Self {
1518 Self::from(..)
1519 }
1520
1521 /// Narrow the supported range
1522 pub fn range<B: RangeBounds<u64>>(mut self, range: B) -> Self {
1523 // Consideration: when the user does `value_parser!(u8).range()`
1524 // - Avoid programming mistakes by accidentally expanding the range
1525 // - Make it convenient to limit the range like with `..10`
1526 let start = match range.start_bound() {
1527 l @ std::ops::Bound::Included(i) => {
1528 debug_assert!(
1529 self.bounds.contains(i),
1530 "{} must be in {:?}",
1531 i,
1532 self.bounds
1533 );
1534 l.cloned()
1535 }
1536 l @ std::ops::Bound::Excluded(i) => {
1537 debug_assert!(
1538 self.bounds.contains(&i.saturating_add(1)),
1539 "{} must be in {:?}",
1540 i,
1541 self.bounds
1542 );
1543 l.cloned()
1544 }
1545 std::ops::Bound::Unbounded => self.bounds.start_bound().cloned(),
1546 };
1547 let end = match range.end_bound() {
1548 l @ std::ops::Bound::Included(i) => {
1549 debug_assert!(
1550 self.bounds.contains(i),
1551 "{} must be in {:?}",
1552 i,
1553 self.bounds
1554 );
1555 l.cloned()
1556 }
1557 l @ std::ops::Bound::Excluded(i) => {
1558 debug_assert!(
1559 self.bounds.contains(&i.saturating_sub(1)),
1560 "{} must be in {:?}",
1561 i,
1562 self.bounds
1563 );
1564 l.cloned()
1565 }
1566 std::ops::Bound::Unbounded => self.bounds.end_bound().cloned(),
1567 };
1568 self.bounds = (start, end);
1569 self
1570 }
1571
1572 fn format_bounds(&self) -> String {
1573 let mut result = match self.bounds.0 {
1574 std::ops::Bound::Included(i) => i.to_string(),
1575 std::ops::Bound::Excluded(i) => i.saturating_add(1).to_string(),
1576 std::ops::Bound::Unbounded => u64::MIN.to_string(),
1577 };
1578 result.push_str("..");
1579 match self.bounds.1 {
1580 std::ops::Bound::Included(i) => {
1581 result.push('=');
1582 result.push_str(&i.to_string());
1583 }
1584 std::ops::Bound::Excluded(i) => {
1585 result.push_str(&i.to_string());
1586 }
1587 std::ops::Bound::Unbounded => {
1588 result.push_str(&u64::MAX.to_string());
1589 }
1590 }
1591 result
1592 }
1593}
1594
1595impl<T: TryFrom<u64> + Clone + Send + Sync + 'static> TypedValueParser for RangedU64ValueParser<T>
1596where
1597 <T as TryFrom<u64>>::Error: Send + Sync + 'static + std::error::Error + ToString,
1598{
1599 type Value = T;
1600
1601 fn parse_ref(
1602 &self,
1603 cmd: &crate::Command,
1604 arg: Option<&crate::Arg>,
1605 raw_value: &std::ffi::OsStr,
1606 ) -> Result<Self::Value, crate::Error> {
1607 let value = ok!(raw_value.to_str().ok_or_else(|| {
1608 crate::Error::invalid_utf8(
1609 cmd,
1610 crate::output::Usage::new(cmd).create_usage_with_title(&[]),
1611 )
1612 }));
1613 let value = ok!(value.parse::<u64>().map_err(|err| {
1614 let arg = arg
1615 .map(|a| a.to_string())
1616 .unwrap_or_else(|| "...".to_owned());
1617 crate::Error::value_validation(
1618 arg,
1619 raw_value.to_string_lossy().into_owned(),
1620 err.into(),
1621 )
1622 .with_cmd(cmd)
1623 }));
1624 if !self.bounds.contains(&value) {
1625 let arg = arg
1626 .map(|a| a.to_string())
1627 .unwrap_or_else(|| "...".to_owned());
1628 return Err(crate::Error::value_validation(
1629 arg,
1630 raw_value.to_string_lossy().into_owned(),
1631 format!("{} is not in {}", value, self.format_bounds()).into(),
1632 )
1633 .with_cmd(cmd));
1634 }
1635
1636 let value: Result<Self::Value, _> = value.try_into();
1637 let value = ok!(value.map_err(|err| {
1638 let arg = arg
1639 .map(|a| a.to_string())
1640 .unwrap_or_else(|| "...".to_owned());
1641 crate::Error::value_validation(
1642 arg,
1643 raw_value.to_string_lossy().into_owned(),
1644 err.into(),
1645 )
1646 .with_cmd(cmd)
1647 }));
1648
1649 Ok(value)
1650 }
1651}
1652
1653impl<T: TryFrom<u64>, B: RangeBounds<u64>> From<B> for RangedU64ValueParser<T> {
1654 fn from(range: B) -> Self {
1655 Self {
1656 bounds: (range.start_bound().cloned(), range.end_bound().cloned()),
1657 target: Default::default(),
1658 }
1659 }
1660}
1661
1662impl<T: TryFrom<u64>> Default for RangedU64ValueParser<T> {
1663 fn default() -> Self {
1664 Self::new()
1665 }
1666}
1667
1668/// Implementation for [`ValueParser::bool`]
1669///
1670/// Useful for composing new [`TypedValueParser`]s
1671#[derive(Copy, Clone, Debug)]
1672#[non_exhaustive]
1673pub struct BoolValueParser {}
1674
1675impl BoolValueParser {
1676 /// Implementation for [`ValueParser::bool`]
1677 pub fn new() -> Self {
1678 Self {}
1679 }
1680
1681 fn possible_values() -> impl Iterator<Item = crate::builder::PossibleValue> {
1682 ["true", "false"]
1683 .iter()
1684 .copied()
1685 .map(crate::builder::PossibleValue::new)
1686 }
1687}
1688
1689impl TypedValueParser for BoolValueParser {
1690 type Value = bool;
1691
1692 fn parse_ref(
1693 &self,
1694 cmd: &crate::Command,
1695 arg: Option<&crate::Arg>,
1696 value: &std::ffi::OsStr,
1697 ) -> Result<Self::Value, crate::Error> {
1698 let value = if value == std::ffi::OsStr::new("true") {
1699 true
1700 } else if value == std::ffi::OsStr::new("false") {
1701 false
1702 } else {
1703 // Intentionally showing hidden as we hide all of them
1704 let possible_vals = Self::possible_values()
1705 .map(|v| v.get_name().to_owned())
1706 .collect::<Vec<_>>();
1707
1708 return Err(crate::Error::invalid_value(
1709 cmd,
1710 value.to_string_lossy().into_owned(),
1711 &possible_vals,
1712 arg.map(ToString::to_string)
1713 .unwrap_or_else(|| "...".to_owned()),
1714 ));
1715 };
1716 Ok(value)
1717 }
1718
1719 fn possible_values(
1720 &self,
1721 ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> {
1722 Some(Box::new(Self::possible_values()))
1723 }
1724}
1725
1726impl Default for BoolValueParser {
1727 fn default() -> Self {
1728 Self::new()
1729 }
1730}
1731
1732/// Parse false-like string values, everything else is `true`
1733///
1734/// See also:
1735/// - [`ValueParser::bool`] for assuming non-false is true
1736/// - [`BoolishValueParser`] for different human readable bool representations
1737///
1738/// # Example
1739///
1740/// Usage:
1741/// ```rust
1742/// # use clap_builder as clap;
1743/// let mut cmd = clap::Command::new("raw")
1744/// .arg(
1745/// clap::Arg::new("append")
1746/// .value_parser(clap::builder::FalseyValueParser::new())
1747/// .required(true)
1748/// );
1749///
1750/// let m = cmd.try_get_matches_from_mut(["cmd", "true"]).unwrap();
1751/// let port: bool = *m.get_one("append")
1752/// .expect("required");
1753/// assert_eq!(port, true);
1754/// ```
1755///
1756/// Semantics:
1757/// ```rust
1758/// # use clap_builder as clap;
1759/// # use std::ffi::OsStr;
1760/// # use clap::builder::TypedValueParser;
1761/// # let cmd = clap::Command::new("test");
1762/// # let arg = None;
1763/// let value_parser = clap::builder::FalseyValueParser::new();
1764/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).unwrap(), true);
1765/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("100")).unwrap(), true);
1766/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).unwrap(), false);
1767/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("false")).unwrap(), false);
1768/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("No")).unwrap(), false);
1769/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oFF")).unwrap(), false);
1770/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0")).unwrap(), false);
1771/// ```
1772#[derive(Copy, Clone, Debug)]
1773#[non_exhaustive]
1774pub struct FalseyValueParser {}
1775
1776impl FalseyValueParser {
1777 /// Parse false-like string values, everything else is `true`
1778 pub fn new() -> Self {
1779 Self {}
1780 }
1781
1782 fn possible_values() -> impl Iterator<Item = crate::builder::PossibleValue> {
1783 crate::util::TRUE_LITERALS
1784 .iter()
1785 .chain(crate::util::FALSE_LITERALS.iter())
1786 .copied()
1787 .map(|l| crate::builder::PossibleValue::new(l).hide(l != "true" && l != "false"))
1788 }
1789}
1790
1791impl TypedValueParser for FalseyValueParser {
1792 type Value = bool;
1793
1794 fn parse_ref(
1795 &self,
1796 cmd: &crate::Command,
1797 _arg: Option<&crate::Arg>,
1798 value: &std::ffi::OsStr,
1799 ) -> Result<Self::Value, crate::Error> {
1800 let value = ok!(value.to_str().ok_or_else(|| {
1801 crate::Error::invalid_utf8(
1802 cmd,
1803 crate::output::Usage::new(cmd).create_usage_with_title(&[]),
1804 )
1805 }));
1806 let value = if value.is_empty() {
1807 false
1808 } else {
1809 crate::util::str_to_bool(value).unwrap_or(true)
1810 };
1811 Ok(value)
1812 }
1813
1814 fn possible_values(
1815 &self,
1816 ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> {
1817 Some(Box::new(Self::possible_values()))
1818 }
1819}
1820
1821impl Default for FalseyValueParser {
1822 fn default() -> Self {
1823 Self::new()
1824 }
1825}
1826
1827/// Parse bool-like string values, everything else is `true`
1828///
1829/// See also:
1830/// - [`ValueParser::bool`] for different human readable bool representations
1831/// - [`FalseyValueParser`] for assuming non-false is true
1832///
1833/// # Example
1834///
1835/// Usage:
1836/// ```rust
1837/// # use clap_builder as clap;
1838/// let mut cmd = clap::Command::new("raw")
1839/// .arg(
1840/// clap::Arg::new("append")
1841/// .value_parser(clap::builder::BoolishValueParser::new())
1842/// .required(true)
1843/// );
1844///
1845/// let m = cmd.try_get_matches_from_mut(["cmd", "true"]).unwrap();
1846/// let port: bool = *m.get_one("append")
1847/// .expect("required");
1848/// assert_eq!(port, true);
1849/// ```
1850///
1851/// Semantics:
1852/// ```rust
1853/// # use clap_builder as clap;
1854/// # use std::ffi::OsStr;
1855/// # use clap::builder::TypedValueParser;
1856/// # let cmd = clap::Command::new("test");
1857/// # let arg = None;
1858/// let value_parser = clap::builder::BoolishValueParser::new();
1859/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).is_err());
1860/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err());
1861/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("100")).is_err());
1862/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("true")).unwrap(), true);
1863/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("Yes")).unwrap(), true);
1864/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oN")).unwrap(), true);
1865/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("1")).unwrap(), true);
1866/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("false")).unwrap(), false);
1867/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("No")).unwrap(), false);
1868/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oFF")).unwrap(), false);
1869/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0")).unwrap(), false);
1870/// ```
1871#[derive(Copy, Clone, Debug)]
1872#[non_exhaustive]
1873pub struct BoolishValueParser {}
1874
1875impl BoolishValueParser {
1876 /// Parse bool-like string values, everything else is an error.
1877 pub fn new() -> Self {
1878 Self {}
1879 }
1880
1881 fn possible_values() -> impl Iterator<Item = crate::builder::PossibleValue> {
1882 crate::util::TRUE_LITERALS
1883 .iter()
1884 .chain(crate::util::FALSE_LITERALS.iter())
1885 .copied()
1886 .map(|l| crate::builder::PossibleValue::new(l).hide(l != "true" && l != "false"))
1887 }
1888}
1889
1890impl TypedValueParser for BoolishValueParser {
1891 type Value = bool;
1892
1893 fn parse_ref(
1894 &self,
1895 cmd: &crate::Command,
1896 arg: Option<&crate::Arg>,
1897 value: &std::ffi::OsStr,
1898 ) -> Result<Self::Value, crate::Error> {
1899 let value = ok!(value.to_str().ok_or_else(|| {
1900 crate::Error::invalid_utf8(
1901 cmd,
1902 crate::output::Usage::new(cmd).create_usage_with_title(&[]),
1903 )
1904 }));
1905 let value = ok!(crate::util::str_to_bool(value).ok_or_else(|| {
1906 let arg = arg
1907 .map(|a| a.to_string())
1908 .unwrap_or_else(|| "...".to_owned());
1909 crate::Error::value_validation(arg, value.to_owned(), "value was not a boolean".into())
1910 .with_cmd(cmd)
1911 }));
1912 Ok(value)
1913 }
1914
1915 fn possible_values(
1916 &self,
1917 ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> {
1918 Some(Box::new(Self::possible_values()))
1919 }
1920}
1921
1922impl Default for BoolishValueParser {
1923 fn default() -> Self {
1924 Self::new()
1925 }
1926}
1927
1928/// Parse non-empty string values
1929///
1930/// See also:
1931/// - [`ValueParser::string`]
1932///
1933/// # Example
1934///
1935/// Usage:
1936/// ```rust
1937/// # use clap_builder as clap;
1938/// let mut cmd = clap::Command::new("raw")
1939/// .arg(
1940/// clap::Arg::new("append")
1941/// .value_parser(clap::builder::NonEmptyStringValueParser::new())
1942/// .required(true)
1943/// );
1944///
1945/// let m = cmd.try_get_matches_from_mut(["cmd", "true"]).unwrap();
1946/// let port: &String = m.get_one("append")
1947/// .expect("required");
1948/// assert_eq!(port, "true");
1949/// ```
1950///
1951/// Semantics:
1952/// ```rust
1953/// # use clap_builder as clap;
1954/// # use std::ffi::OsStr;
1955/// # use clap::builder::TypedValueParser;
1956/// # let cmd = clap::Command::new("test");
1957/// # let arg = None;
1958/// let value_parser = clap::builder::NonEmptyStringValueParser::new();
1959/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).unwrap(), "random");
1960/// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err());
1961/// ```
1962#[derive(Copy, Clone, Debug)]
1963#[non_exhaustive]
1964pub struct NonEmptyStringValueParser {}
1965
1966impl NonEmptyStringValueParser {
1967 /// Parse non-empty string values
1968 pub fn new() -> Self {
1969 Self {}
1970 }
1971}
1972
1973impl TypedValueParser for NonEmptyStringValueParser {
1974 type Value = String;
1975
1976 fn parse_ref(
1977 &self,
1978 cmd: &crate::Command,
1979 arg: Option<&crate::Arg>,
1980 value: &std::ffi::OsStr,
1981 ) -> Result<Self::Value, crate::Error> {
1982 if value.is_empty() {
1983 return Err(crate::Error::empty_value(
1984 cmd,
1985 &[],
1986 arg.map(ToString::to_string)
1987 .unwrap_or_else(|| "...".to_owned()),
1988 ));
1989 }
1990 let value = ok!(value.to_str().ok_or_else(|| {
1991 crate::Error::invalid_utf8(
1992 cmd,
1993 crate::output::Usage::new(cmd).create_usage_with_title(&[]),
1994 )
1995 }));
1996 Ok(value.to_owned())
1997 }
1998}
1999
2000impl Default for NonEmptyStringValueParser {
2001 fn default() -> Self {
2002 Self::new()
2003 }
2004}
2005
2006/// Adapt a `TypedValueParser` from one value to another
2007///
2008/// See [`TypedValueParser::map`]
2009#[derive(Clone, Debug)]
2010pub struct MapValueParser<P, F> {
2011 parser: P,
2012 func: F,
2013}
2014
2015impl<P, F, T> MapValueParser<P, F>
2016where
2017 P: TypedValueParser,
2018 P::Value: Send + Sync + Clone,
2019 F: Fn(P::Value) -> T + Clone,
2020 T: Send + Sync + Clone,
2021{
2022 fn new(parser: P, func: F) -> Self {
2023 Self { parser, func }
2024 }
2025}
2026
2027impl<P, F, T> TypedValueParser for MapValueParser<P, F>
2028where
2029 P: TypedValueParser,
2030 P::Value: Send + Sync + Clone,
2031 F: Fn(P::Value) -> T + Clone + Send + Sync + 'static,
2032 T: Send + Sync + Clone,
2033{
2034 type Value = T;
2035
2036 fn parse_ref(
2037 &self,
2038 cmd: &crate::Command,
2039 arg: Option<&crate::Arg>,
2040 value: &std::ffi::OsStr,
2041 ) -> Result<Self::Value, crate::Error> {
2042 let value = ok!(self.parser.parse_ref(cmd, arg, value));
2043 let value = (self.func)(value);
2044 Ok(value)
2045 }
2046
2047 fn parse(
2048 &self,
2049 cmd: &crate::Command,
2050 arg: Option<&crate::Arg>,
2051 value: std::ffi::OsString,
2052 ) -> Result<Self::Value, crate::Error> {
2053 let value = ok!(self.parser.parse(cmd, arg, value));
2054 let value = (self.func)(value);
2055 Ok(value)
2056 }
2057
2058 fn possible_values(
2059 &self,
2060 ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> {
2061 self.parser.possible_values()
2062 }
2063}
2064
2065/// Adapt a `TypedValueParser` from one value to another
2066///
2067/// See [`TypedValueParser::try_map`]
2068#[derive(Clone, Debug)]
2069pub struct TryMapValueParser<P, F> {
2070 parser: P,
2071 func: F,
2072}
2073
2074impl<P, F, T, E> TryMapValueParser<P, F>
2075where
2076 P: TypedValueParser,
2077 P::Value: Send + Sync + Clone,
2078 F: Fn(P::Value) -> Result<T, E> + Clone + Send + Sync + 'static,
2079 T: Send + Sync + Clone,
2080 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
2081{
2082 fn new(parser: P, func: F) -> Self {
2083 Self { parser, func }
2084 }
2085}
2086
2087impl<P, F, T, E> TypedValueParser for TryMapValueParser<P, F>
2088where
2089 P: TypedValueParser,
2090 P::Value: Send + Sync + Clone,
2091 F: Fn(P::Value) -> Result<T, E> + Clone + Send + Sync + 'static,
2092 T: Send + Sync + Clone,
2093 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
2094{
2095 type Value = T;
2096
2097 fn parse_ref(
2098 &self,
2099 cmd: &crate::Command,
2100 arg: Option<&crate::Arg>,
2101 value: &std::ffi::OsStr,
2102 ) -> Result<Self::Value, crate::Error> {
2103 let mid_value = ok!(self.parser.parse_ref(cmd, arg, value));
2104 let value = ok!((self.func)(mid_value).map_err(|e| {
2105 let arg = arg
2106 .map(|a| a.to_string())
2107 .unwrap_or_else(|| "...".to_owned());
2108 crate::Error::value_validation(arg, value.to_string_lossy().into_owned(), e.into())
2109 .with_cmd(cmd)
2110 }));
2111 Ok(value)
2112 }
2113
2114 fn possible_values(
2115 &self,
2116 ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> {
2117 self.parser.possible_values()
2118 }
2119}
2120
2121/// When encountered, report [`ErrorKind::UnknownArgument`][crate::error::ErrorKind::UnknownArgument]
2122///
2123/// Useful to help users migrate, either from old versions or similar tools.
2124///
2125/// # Examples
2126///
2127/// ```rust
2128/// # use clap_builder as clap;
2129/// # use clap::Command;
2130/// # use clap::Arg;
2131/// let cmd = Command::new("mycmd")
2132/// .args([
2133/// Arg::new("current-dir")
2134/// .short('C'),
2135/// Arg::new("current-dir-unknown")
2136/// .long("cwd")
2137/// .aliases(["current-dir", "directory", "working-directory", "root"])
2138/// .value_parser(clap::builder::UnknownArgumentValueParser::suggest_arg("-C"))
2139/// .hide(true),
2140/// ]);
2141///
2142/// // Use a supported version of the argument
2143/// let matches = cmd.clone().try_get_matches_from(["mycmd", "-C", ".."]).unwrap();
2144/// assert!(matches.contains_id("current-dir"));
2145/// assert_eq!(
2146/// matches.get_many::<String>("current-dir").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
2147/// vec![".."]
2148/// );
2149///
2150/// // Use one of the invalid versions
2151/// let err = cmd.try_get_matches_from(["mycmd", "--cwd", ".."]).unwrap_err();
2152/// assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
2153/// ```
2154#[derive(Clone, Debug)]
2155pub struct UnknownArgumentValueParser {
2156 arg: Option<Str>,
2157 suggestions: Vec<StyledStr>,
2158}
2159
2160impl UnknownArgumentValueParser {
2161 /// Suggest an alternative argument
2162 pub fn suggest_arg(arg: impl Into<Str>) -> Self {
2163 Self {
2164 arg: Some(arg.into()),
2165 suggestions: Default::default(),
2166 }
2167 }
2168
2169 /// Provide a general suggestion
2170 pub fn suggest(text: impl Into<StyledStr>) -> Self {
2171 Self {
2172 arg: Default::default(),
2173 suggestions: vec![text.into()],
2174 }
2175 }
2176
2177 /// Extend the suggestions
2178 pub fn and_suggest(mut self, text: impl Into<StyledStr>) -> Self {
2179 self.suggestions.push(text.into());
2180 self
2181 }
2182}
2183
2184impl TypedValueParser for UnknownArgumentValueParser {
2185 type Value = String;
2186
2187 fn parse_ref(
2188 &self,
2189 cmd: &crate::Command,
2190 arg: Option<&crate::Arg>,
2191 value: &std::ffi::OsStr,
2192 ) -> Result<Self::Value, crate::Error> {
2193 TypedValueParser::parse_ref_(self, cmd, arg, value, ValueSource::CommandLine)
2194 }
2195
2196 fn parse_ref_(
2197 &self,
2198 cmd: &crate::Command,
2199 arg: Option<&crate::Arg>,
2200 _value: &std::ffi::OsStr,
2201 source: ValueSource,
2202 ) -> Result<Self::Value, crate::Error> {
2203 match source {
2204 ValueSource::DefaultValue => {
2205 TypedValueParser::parse_ref_(&StringValueParser::new(), cmd, arg, _value, source)
2206 }
2207 ValueSource::EnvVariable | ValueSource::CommandLine => {
2208 let arg = match arg {
2209 Some(arg) => arg.to_string(),
2210 None => "..".to_owned(),
2211 };
2212 let err = crate::Error::unknown_argument(
2213 cmd,
2214 arg,
2215 self.arg.as_ref().map(|s| (s.as_str().to_owned(), None)),
2216 false,
2217 crate::output::Usage::new(cmd).create_usage_with_title(&[]),
2218 );
2219 #[cfg(feature = "error-context")]
2220 let err = {
2221 debug_assert_eq!(
2222 err.get(crate::error::ContextKind::Suggested),
2223 None,
2224 "Assuming `Error::unknown_argument` doesn't apply any `Suggested` so we can without caution"
2225 );
2226 err.insert_context_unchecked(
2227 crate::error::ContextKind::Suggested,
2228 crate::error::ContextValue::StyledStrs(self.suggestions.clone()),
2229 )
2230 };
2231 Err(err)
2232 }
2233 }
2234 }
2235}
2236
2237/// Register a type with [`value_parser!`][crate::value_parser!]
2238///
2239/// # Example
2240///
2241/// ```rust
2242/// # use clap_builder as clap;
2243/// #[derive(Copy, Clone, Debug)]
2244/// pub struct Custom(u32);
2245///
2246/// impl clap::builder::ValueParserFactory for Custom {
2247/// type Parser = CustomValueParser;
2248/// fn value_parser() -> Self::Parser {
2249/// CustomValueParser
2250/// }
2251/// }
2252///
2253/// #[derive(Clone, Debug)]
2254/// pub struct CustomValueParser;
2255/// impl clap::builder::TypedValueParser for CustomValueParser {
2256/// type Value = Custom;
2257///
2258/// fn parse_ref(
2259/// &self,
2260/// cmd: &clap::Command,
2261/// arg: Option<&clap::Arg>,
2262/// value: &std::ffi::OsStr,
2263/// ) -> Result<Self::Value, clap::Error> {
2264/// let inner = clap::value_parser!(u32);
2265/// let val = inner.parse_ref(cmd, arg, value)?;
2266/// Ok(Custom(val))
2267/// }
2268/// }
2269///
2270/// let parser: CustomValueParser = clap::value_parser!(Custom);
2271/// ```
2272pub trait ValueParserFactory {
2273 /// Generated parser, usually [`ValueParser`].
2274 ///
2275 /// It should at least be a type that supports `Into<ValueParser>`. A non-`ValueParser` type
2276 /// allows the caller to do further initialization on the parser.
2277 type Parser;
2278
2279 /// Create the specified [`Self::Parser`]
2280 fn value_parser() -> Self::Parser;
2281}
2282impl ValueParserFactory for String {
2283 type Parser = ValueParser;
2284 fn value_parser() -> Self::Parser {
2285 ValueParser::string() // Default `clap_derive` to optimized implementation
2286 }
2287}
2288impl ValueParserFactory for Box<str> {
2289 type Parser = MapValueParser<StringValueParser, fn(String) -> Box<str>>;
2290 fn value_parser() -> Self::Parser {
2291 StringValueParser::new().map(String::into_boxed_str)
2292 }
2293}
2294impl ValueParserFactory for std::ffi::OsString {
2295 type Parser = ValueParser;
2296 fn value_parser() -> Self::Parser {
2297 ValueParser::os_string() // Default `clap_derive` to optimized implementation
2298 }
2299}
2300impl ValueParserFactory for Box<std::ffi::OsStr> {
2301 type Parser =
2302 MapValueParser<OsStringValueParser, fn(std::ffi::OsString) -> Box<std::ffi::OsStr>>;
2303 fn value_parser() -> Self::Parser {
2304 OsStringValueParser::new().map(std::ffi::OsString::into_boxed_os_str)
2305 }
2306}
2307impl ValueParserFactory for std::path::PathBuf {
2308 type Parser = ValueParser;
2309 fn value_parser() -> Self::Parser {
2310 ValueParser::path_buf() // Default `clap_derive` to optimized implementation
2311 }
2312}
2313impl ValueParserFactory for Box<std::path::Path> {
2314 type Parser =
2315 MapValueParser<PathBufValueParser, fn(std::path::PathBuf) -> Box<std::path::Path>>;
2316 fn value_parser() -> Self::Parser {
2317 PathBufValueParser::new().map(std::path::PathBuf::into_boxed_path)
2318 }
2319}
2320impl ValueParserFactory for bool {
2321 type Parser = ValueParser;
2322 fn value_parser() -> Self::Parser {
2323 ValueParser::bool() // Default `clap_derive` to optimized implementation
2324 }
2325}
2326impl ValueParserFactory for u8 {
2327 type Parser = RangedI64ValueParser<u8>;
2328 fn value_parser() -> Self::Parser {
2329 let start: i64 = u8::MIN.into();
2330 let end: i64 = u8::MAX.into();
2331 RangedI64ValueParser::new().range(start..=end)
2332 }
2333}
2334impl ValueParserFactory for i8 {
2335 type Parser = RangedI64ValueParser<i8>;
2336 fn value_parser() -> Self::Parser {
2337 let start: i64 = i8::MIN.into();
2338 let end: i64 = i8::MAX.into();
2339 RangedI64ValueParser::new().range(start..=end)
2340 }
2341}
2342impl ValueParserFactory for u16 {
2343 type Parser = RangedI64ValueParser<u16>;
2344 fn value_parser() -> Self::Parser {
2345 let start: i64 = u16::MIN.into();
2346 let end: i64 = u16::MAX.into();
2347 RangedI64ValueParser::new().range(start..=end)
2348 }
2349}
2350impl ValueParserFactory for i16 {
2351 type Parser = RangedI64ValueParser<i16>;
2352 fn value_parser() -> Self::Parser {
2353 let start: i64 = i16::MIN.into();
2354 let end: i64 = i16::MAX.into();
2355 RangedI64ValueParser::new().range(start..=end)
2356 }
2357}
2358impl ValueParserFactory for u32 {
2359 type Parser = RangedI64ValueParser<u32>;
2360 fn value_parser() -> Self::Parser {
2361 let start: i64 = u32::MIN.into();
2362 let end: i64 = u32::MAX.into();
2363 RangedI64ValueParser::new().range(start..=end)
2364 }
2365}
2366impl ValueParserFactory for i32 {
2367 type Parser = RangedI64ValueParser<i32>;
2368 fn value_parser() -> Self::Parser {
2369 let start: i64 = i32::MIN.into();
2370 let end: i64 = i32::MAX.into();
2371 RangedI64ValueParser::new().range(start..=end)
2372 }
2373}
2374impl ValueParserFactory for u64 {
2375 type Parser = RangedU64ValueParser<u64>;
2376 fn value_parser() -> Self::Parser {
2377 RangedU64ValueParser::new()
2378 }
2379}
2380impl ValueParserFactory for i64 {
2381 type Parser = RangedI64ValueParser<i64>;
2382 fn value_parser() -> Self::Parser {
2383 RangedI64ValueParser::new()
2384 }
2385}
2386impl<T> ValueParserFactory for std::num::Wrapping<T>
2387where
2388 T: ValueParserFactory,
2389 <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>,
2390 T: Send + Sync + Clone,
2391{
2392 type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> std::num::Wrapping<T>>;
2393 fn value_parser() -> Self::Parser {
2394 T::value_parser().map(std::num::Wrapping)
2395 }
2396}
2397impl<T> ValueParserFactory for Box<T>
2398where
2399 T: ValueParserFactory,
2400 <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>,
2401 T: Send + Sync + Clone,
2402{
2403 type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> Box<T>>;
2404 fn value_parser() -> Self::Parser {
2405 T::value_parser().map(Box::new)
2406 }
2407}
2408impl<T> ValueParserFactory for std::sync::Arc<T>
2409where
2410 T: ValueParserFactory,
2411 <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>,
2412 T: Send + Sync + Clone,
2413{
2414 type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> std::sync::Arc<T>>;
2415 fn value_parser() -> Self::Parser {
2416 T::value_parser().map(std::sync::Arc::new)
2417 }
2418}
2419
2420#[doc(hidden)]
2421#[derive(Debug)]
2422#[allow(non_camel_case_types)]
2423pub struct _infer_ValueParser_for<T>(std::marker::PhantomData<T>);
2424
2425impl<T> _infer_ValueParser_for<T> {
2426 #[doc(hidden)]
2427 #[allow(clippy::new_without_default)]
2428 pub fn new() -> Self {
2429 Self(Default::default())
2430 }
2431}
2432
2433/// Unstable [`ValueParser`]
2434///
2435/// Implementation may change to more specific instance in the future
2436#[doc(hidden)]
2437#[derive(Debug)]
2438pub struct _AnonymousValueParser(ValueParser);
2439
2440#[doc(hidden)]
2441pub mod impl_prelude {
2442 use super::*;
2443
2444 #[doc(hidden)]
2445 #[allow(non_camel_case_types)]
2446 pub trait _impls_ValueParserFactory: private::_impls_ValueParserFactorySealed {
2447 type Parser;
2448 fn value_parser(&self) -> Self::Parser;
2449 }
2450 impl<P: ValueParserFactory> _impls_ValueParserFactory for &&&&&&_infer_ValueParser_for<P> {
2451 type Parser = P::Parser;
2452 fn value_parser(&self) -> Self::Parser {
2453 P::value_parser()
2454 }
2455 }
2456
2457 #[doc(hidden)]
2458 #[allow(non_camel_case_types)]
2459 pub trait _impls_ValueEnum: private::_impls_ValueEnumSealed {
2460 type Output;
2461
2462 fn value_parser(&self) -> Self::Output;
2463 }
2464 impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> _impls_ValueEnum
2465 for &&&&&_infer_ValueParser_for<E>
2466 {
2467 type Output = EnumValueParser<E>;
2468
2469 fn value_parser(&self) -> Self::Output {
2470 EnumValueParser::<E>::new()
2471 }
2472 }
2473
2474 #[doc(hidden)]
2475 #[allow(non_camel_case_types)]
2476 pub trait _impls_From_OsString: private::_impls_From_OsStringSealed {
2477 fn value_parser(&self) -> _AnonymousValueParser;
2478 }
2479 impl<FromOsString> _impls_From_OsString for &&&&_infer_ValueParser_for<FromOsString>
2480 where
2481 FromOsString: From<std::ffi::OsString> + std::any::Any + Clone + Send + Sync + 'static,
2482 {
2483 fn value_parser(&self) -> _AnonymousValueParser {
2484 _AnonymousValueParser(
2485 OsStringValueParser::new()
2486 .map(|s| FromOsString::from(s))
2487 .into(),
2488 )
2489 }
2490 }
2491
2492 #[doc(hidden)]
2493 #[allow(non_camel_case_types)]
2494 pub trait _impls_From_OsStr: private::_impls_From_OsStrSealed {
2495 fn value_parser(&self) -> _AnonymousValueParser;
2496 }
2497 impl<FromOsStr> _impls_From_OsStr for &&&_infer_ValueParser_for<FromOsStr>
2498 where
2499 FromOsStr:
2500 for<'s> From<&'s std::ffi::OsStr> + std::any::Any + Clone + Send + Sync + 'static,
2501 {
2502 fn value_parser(&self) -> _AnonymousValueParser {
2503 _AnonymousValueParser(
2504 OsStringValueParser::new()
2505 .map(|s| FromOsStr::from(&s))
2506 .into(),
2507 )
2508 }
2509 }
2510
2511 #[doc(hidden)]
2512 #[allow(non_camel_case_types)]
2513 pub trait _impls_From_String: private::_impls_From_StringSealed {
2514 fn value_parser(&self) -> _AnonymousValueParser;
2515 }
2516 impl<FromString> _impls_From_String for &&_infer_ValueParser_for<FromString>
2517 where
2518 FromString: From<String> + std::any::Any + Clone + Send + Sync + 'static,
2519 {
2520 fn value_parser(&self) -> _AnonymousValueParser {
2521 _AnonymousValueParser(StringValueParser::new().map(|s| FromString::from(s)).into())
2522 }
2523 }
2524
2525 #[doc(hidden)]
2526 #[allow(non_camel_case_types)]
2527 pub trait _impls_From_str: private::_impls_From_strSealed {
2528 fn value_parser(&self) -> _AnonymousValueParser;
2529 }
2530 impl<FromStr> _impls_From_str for &_infer_ValueParser_for<FromStr>
2531 where
2532 FromStr: for<'s> From<&'s str> + std::any::Any + Clone + Send + Sync + 'static,
2533 {
2534 fn value_parser(&self) -> _AnonymousValueParser {
2535 _AnonymousValueParser(StringValueParser::new().map(|s| FromStr::from(&s)).into())
2536 }
2537 }
2538
2539 #[doc(hidden)]
2540 #[allow(non_camel_case_types)]
2541 pub trait _impls_FromStr: private::_impls_FromStrSealed {
2542 fn value_parser(&self) -> _AnonymousValueParser;
2543 }
2544 impl<Parse> _impls_FromStr for _infer_ValueParser_for<Parse>
2545 where
2546 Parse: std::str::FromStr + std::any::Any + Clone + Send + Sync + 'static,
2547 <Parse as std::str::FromStr>::Err: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
2548 {
2549 fn value_parser(&self) -> _AnonymousValueParser {
2550 let func: fn(&str) -> Result<Parse, <Parse as std::str::FromStr>::Err> =
2551 Parse::from_str;
2552 _AnonymousValueParser(ValueParser::new(func))
2553 }
2554 }
2555}
2556
2557/// Select a [`ValueParser`] implementation from the intended type
2558///
2559/// Supported types
2560/// - [`ValueParserFactory` types][ValueParserFactory], including
2561/// - [Native types][ValueParser]: `bool`, `String`, `OsString`, `PathBuf`
2562/// - [Ranged numeric types][RangedI64ValueParser]: `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`
2563/// - [`ValueEnum` types][crate::ValueEnum]
2564/// - [`From<OsString>` types][std::convert::From] and [`From<&OsStr>` types][std::convert::From]
2565/// - [`From<String>` types][std::convert::From] and [`From<&str>` types][std::convert::From]
2566/// - [`FromStr` types][std::str::FromStr], including usize, isize
2567///
2568/// # Example
2569///
2570/// Usage:
2571/// ```rust
2572/// # use clap_builder as clap;
2573/// # use std::path::PathBuf;
2574/// # use std::path::Path;
2575/// let mut cmd = clap::Command::new("raw")
2576/// .arg(
2577/// clap::Arg::new("output")
2578/// .value_parser(clap::value_parser!(PathBuf))
2579/// .required(true)
2580/// );
2581///
2582/// let m = cmd.try_get_matches_from_mut(["cmd", "file.txt"]).unwrap();
2583/// let port: &PathBuf = m.get_one("output")
2584/// .expect("required");
2585/// assert_eq!(port, Path::new("file.txt"));
2586/// ```
2587///
2588/// Example mappings:
2589/// ```rust
2590/// # use clap_builder as clap;
2591/// # use clap::ColorChoice;
2592/// // Built-in types
2593/// let parser = clap::value_parser!(String);
2594/// assert_eq!(format!("{parser:?}"), "ValueParser::string");
2595/// let parser = clap::value_parser!(std::ffi::OsString);
2596/// assert_eq!(format!("{parser:?}"), "ValueParser::os_string");
2597/// let parser = clap::value_parser!(std::path::PathBuf);
2598/// assert_eq!(format!("{parser:?}"), "ValueParser::path_buf");
2599/// clap::value_parser!(u16).range(3000..);
2600/// clap::value_parser!(u64).range(3000..);
2601///
2602/// // FromStr types
2603/// let parser = clap::value_parser!(usize);
2604/// assert_eq!(format!("{parser:?}"), "_AnonymousValueParser(ValueParser::other(usize))");
2605///
2606/// // ValueEnum types
2607/// clap::value_parser!(ColorChoice);
2608/// ```
2609#[macro_export]
2610macro_rules! value_parser {
2611 ($name:ty) => {{
2612 use $crate::builder::impl_prelude::*;
2613 let auto = $crate::builder::_infer_ValueParser_for::<$name>::new();
2614 (&&&&&&auto).value_parser()
2615 }};
2616}
2617
2618mod private {
2619 use super::*;
2620
2621 #[allow(non_camel_case_types)]
2622 pub trait _impls_ValueParserFactorySealed {}
2623 impl<P: ValueParserFactory> _impls_ValueParserFactorySealed for &&&&&&_infer_ValueParser_for<P> {}
2624
2625 #[allow(non_camel_case_types)]
2626 pub trait _impls_ValueEnumSealed {}
2627 impl<E: crate::ValueEnum> _impls_ValueEnumSealed for &&&&&_infer_ValueParser_for<E> {}
2628
2629 #[allow(non_camel_case_types)]
2630 pub trait _impls_From_OsStringSealed {}
2631 impl<FromOsString> _impls_From_OsStringSealed for &&&&_infer_ValueParser_for<FromOsString> where
2632 FromOsString: From<std::ffi::OsString> + std::any::Any + Send + Sync + 'static
2633 {
2634 }
2635
2636 #[allow(non_camel_case_types)]
2637 pub trait _impls_From_OsStrSealed {}
2638 impl<FromOsStr> _impls_From_OsStrSealed for &&&_infer_ValueParser_for<FromOsStr> where
2639 FromOsStr: for<'s> From<&'s std::ffi::OsStr> + std::any::Any + Send + Sync + 'static
2640 {
2641 }
2642
2643 #[allow(non_camel_case_types)]
2644 pub trait _impls_From_StringSealed {}
2645 impl<FromString> _impls_From_StringSealed for &&_infer_ValueParser_for<FromString> where
2646 FromString: From<String> + std::any::Any + Send + Sync + 'static
2647 {
2648 }
2649
2650 #[allow(non_camel_case_types)]
2651 pub trait _impls_From_strSealed {}
2652 impl<FromStr> _impls_From_strSealed for &_infer_ValueParser_for<FromStr> where
2653 FromStr: for<'s> From<&'s str> + std::any::Any + Send + Sync + 'static
2654 {
2655 }
2656
2657 #[allow(non_camel_case_types)]
2658 pub trait _impls_FromStrSealed {}
2659 impl<Parse> _impls_FromStrSealed for _infer_ValueParser_for<Parse>
2660 where
2661 Parse: std::str::FromStr + std::any::Any + Send + Sync + 'static,
2662 <Parse as std::str::FromStr>::Err: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
2663 {
2664 }
2665}
2666
2667#[cfg(test)]
2668mod test {
2669 use super::*;
2670
2671 #[test]
2672 fn ensure_typed_applies_to_parse() {
2673 fn parse(_: &str) -> Result<usize, std::io::Error> {
2674 Ok(10)
2675 }
2676 let cmd = crate::Command::new("cmd");
2677 let arg = None;
2678 assert_eq!(
2679 TypedValueParser::parse_ref(&parse, &cmd, arg, std::ffi::OsStr::new("foo")).unwrap(),
2680 10
2681 );
2682 }
2683}