use std::convert::TryInto; use std::ops::RangeBounds; use crate::builder::Str; use crate::builder::StyledStr; use crate::parser::ValueSource; use crate::util::AnyValue; use crate::util::AnyValueId; /// Parse/validate argument values /// /// Specified with [`Arg::value_parser`][crate::Arg::value_parser]. /// /// `ValueParser` defines how to convert a raw argument value into a validated and typed value for /// use within an application. /// /// See /// - [`value_parser!`][crate::value_parser] for automatically selecting an implementation for a given type /// - [`ValueParser::new`] for additional [`TypedValueParser`] that can be used /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("color") /// .long("color") /// .value_parser(["always", "auto", "never"]) /// .default_value("auto") /// ) /// .arg( /// clap::Arg::new("hostname") /// .long("hostname") /// .value_parser(clap::builder::NonEmptyStringValueParser::new()) /// .action(clap::ArgAction::Set) /// .required(true) /// ) /// .arg( /// clap::Arg::new("port") /// .long("port") /// .value_parser(clap::value_parser!(u16).range(3000..)) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut( /// ["cmd", "--hostname", "rust-lang.org", "--port", "3001"] /// ).unwrap(); /// /// let color: &String = m.get_one("color") /// .expect("default"); /// assert_eq!(color, "auto"); /// /// let hostname: &String = m.get_one("hostname") /// .expect("required"); /// assert_eq!(hostname, "rust-lang.org"); /// /// let port: u16 = *m.get_one("port") /// .expect("required"); /// assert_eq!(port, 3001); /// ``` pub struct ValueParser(ValueParserInner); enum ValueParserInner { // Common enough to optimize and for possible values Bool, // Common enough to optimize String, // Common enough to optimize OsString, // Common enough to optimize PathBuf, Other(Box), } impl ValueParser { /// Custom parser for argument values /// /// Pre-existing [`TypedValueParser`] implementations include: /// - `Fn(&str) -> Result` /// - [`EnumValueParser`] and [`PossibleValuesParser`] for static enumerated values /// - [`BoolishValueParser`] and [`FalseyValueParser`] for alternative `bool` implementations /// - [`RangedI64ValueParser`] and [`RangedU64ValueParser`] /// - [`NonEmptyStringValueParser`] /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// type EnvVar = (String, Option); /// fn parse_env_var(env: &str) -> Result { /// if let Some((var, value)) = env.split_once('=') { /// Ok((var.to_owned(), Some(value.to_owned()))) /// } else { /// Ok((env.to_owned(), None)) /// } /// } /// /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("env") /// .value_parser(clap::builder::ValueParser::new(parse_env_var)) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "key=value"]).unwrap(); /// let port: &EnvVar = m.get_one("env") /// .expect("required"); /// assert_eq!(*port, ("key".into(), Some("value".into()))); /// ``` pub fn new

(other: P) -> Self where P: TypedValueParser, { Self(ValueParserInner::Other(Box::new(other))) } /// [`bool`] parser for argument values /// /// See also: /// - [`BoolishValueParser`] for different human readable bool representations /// - [`FalseyValueParser`] for assuming non-false is true /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("download") /// .value_parser(clap::value_parser!(bool)) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "true"]).unwrap(); /// let port: bool = *m.get_one("download") /// .expect("required"); /// assert_eq!(port, true); /// /// assert!(cmd.try_get_matches_from_mut(["cmd", "forever"]).is_err()); /// ``` pub const fn bool() -> Self { Self(ValueParserInner::Bool) } /// [`String`] parser for argument values /// /// See also: /// - [`NonEmptyStringValueParser`] /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("port") /// .value_parser(clap::value_parser!(String)) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "80"]).unwrap(); /// let port: &String = m.get_one("port") /// .expect("required"); /// assert_eq!(port, "80"); /// ``` pub const fn string() -> Self { Self(ValueParserInner::String) } /// [`OsString`][std::ffi::OsString] parser for argument values /// /// # Example /// /// ```rust /// # #[cfg(unix)] { /// # use clap_builder as clap; /// # use clap::{Command, Arg, builder::ValueParser}; /// use std::ffi::OsString; /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; /// let r = Command::new("myprog") /// .arg( /// Arg::new("arg") /// .required(true) /// .value_parser(ValueParser::os_string()) /// ) /// .try_get_matches_from(vec![ /// OsString::from("myprog"), /// OsString::from_vec(vec![0xe9]) /// ]); /// /// assert!(r.is_ok()); /// let m = r.unwrap(); /// let arg: &OsString = m.get_one("arg") /// .expect("required"); /// assert_eq!(arg.as_bytes(), &[0xe9]); /// # } /// ``` pub const fn os_string() -> Self { Self(ValueParserInner::OsString) } /// [`PathBuf`][std::path::PathBuf] parser for argument values /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// # use std::path::PathBuf; /// # use std::path::Path; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("output") /// .value_parser(clap::value_parser!(PathBuf)) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "hello.txt"]).unwrap(); /// let port: &PathBuf = m.get_one("output") /// .expect("required"); /// assert_eq!(port, Path::new("hello.txt")); /// /// assert!(cmd.try_get_matches_from_mut(["cmd", ""]).is_err()); /// ``` pub const fn path_buf() -> Self { Self(ValueParserInner::PathBuf) } } impl ValueParser { /// Parse into a `AnyValue` /// /// When `arg` is `None`, an external subcommand value is being parsed. pub(crate) fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, source: ValueSource, ) -> Result { self.any_value_parser().parse_ref_(cmd, arg, value, source) } /// Describes the content of `AnyValue` pub fn type_id(&self) -> AnyValueId { self.any_value_parser().type_id() } /// Reflect on enumerated value properties /// /// Error checking should not be done with this; it is mostly targeted at user-facing /// applications like errors and completion. pub fn possible_values( &self, ) -> Option + '_>> { self.any_value_parser().possible_values() } fn any_value_parser(&self) -> &dyn AnyValueParser { match &self.0 { ValueParserInner::Bool => &BoolValueParser {}, ValueParserInner::String => &StringValueParser {}, ValueParserInner::OsString => &OsStringValueParser {}, ValueParserInner::PathBuf => &PathBufValueParser {}, ValueParserInner::Other(o) => o.as_ref(), } } } /// Convert a [`TypedValueParser`] to [`ValueParser`] /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("hostname") /// .long("hostname") /// .value_parser(clap::builder::NonEmptyStringValueParser::new()) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut( /// ["cmd", "--hostname", "rust-lang.org"] /// ).unwrap(); /// /// let hostname: &String = m.get_one("hostname") /// .expect("required"); /// assert_eq!(hostname, "rust-lang.org"); /// ``` impl

From

for ValueParser where P: TypedValueParser + Send + Sync + 'static, { fn from(p: P) -> Self { Self::new(p) } } impl From<_AnonymousValueParser> for ValueParser { fn from(p: _AnonymousValueParser) -> Self { p.0 } } /// Create an `i64` [`ValueParser`] from a `N..M` range /// /// See [`RangedI64ValueParser`] for more control over the output type. /// /// See also [`RangedU64ValueParser`] /// /// # Examples /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("port") /// .long("port") /// .value_parser(3000..4000) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "3001"]).unwrap(); /// let port: i64 = *m.get_one("port") /// .expect("required"); /// assert_eq!(port, 3001); /// ``` impl From> for ValueParser { fn from(value: std::ops::Range) -> Self { let inner = RangedI64ValueParser::::new().range(value.start..value.end); Self::from(inner) } } /// Create an `i64` [`ValueParser`] from a `N..=M` range /// /// See [`RangedI64ValueParser`] for more control over the output type. /// /// See also [`RangedU64ValueParser`] /// /// # Examples /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("port") /// .long("port") /// .value_parser(3000..=4000) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "3001"]).unwrap(); /// let port: i64 = *m.get_one("port") /// .expect("required"); /// assert_eq!(port, 3001); /// ``` impl From> for ValueParser { fn from(value: std::ops::RangeInclusive) -> Self { let inner = RangedI64ValueParser::::new().range(value.start()..=value.end()); Self::from(inner) } } /// Create an `i64` [`ValueParser`] from a `N..` range /// /// See [`RangedI64ValueParser`] for more control over the output type. /// /// See also [`RangedU64ValueParser`] /// /// # Examples /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("port") /// .long("port") /// .value_parser(3000..) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "3001"]).unwrap(); /// let port: i64 = *m.get_one("port") /// .expect("required"); /// assert_eq!(port, 3001); /// ``` impl From> for ValueParser { fn from(value: std::ops::RangeFrom) -> Self { let inner = RangedI64ValueParser::::new().range(value.start..); Self::from(inner) } } /// Create an `i64` [`ValueParser`] from a `..M` range /// /// See [`RangedI64ValueParser`] for more control over the output type. /// /// See also [`RangedU64ValueParser`] /// /// # Examples /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("port") /// .long("port") /// .value_parser(..3000) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "80"]).unwrap(); /// let port: i64 = *m.get_one("port") /// .expect("required"); /// assert_eq!(port, 80); /// ``` impl From> for ValueParser { fn from(value: std::ops::RangeTo) -> Self { let inner = RangedI64ValueParser::::new().range(..value.end); Self::from(inner) } } /// Create an `i64` [`ValueParser`] from a `..=M` range /// /// See [`RangedI64ValueParser`] for more control over the output type. /// /// See also [`RangedU64ValueParser`] /// /// # Examples /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("port") /// .long("port") /// .value_parser(..=3000) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "80"]).unwrap(); /// let port: i64 = *m.get_one("port") /// .expect("required"); /// assert_eq!(port, 80); /// ``` impl From> for ValueParser { fn from(value: std::ops::RangeToInclusive) -> Self { let inner = RangedI64ValueParser::::new().range(..=value.end); Self::from(inner) } } /// Create an `i64` [`ValueParser`] from a `..` range /// /// See [`RangedI64ValueParser`] for more control over the output type. /// /// See also [`RangedU64ValueParser`] /// /// # Examples /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("port") /// .long("port") /// .value_parser(..) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "3001"]).unwrap(); /// let port: i64 = *m.get_one("port") /// .expect("required"); /// assert_eq!(port, 3001); /// ``` impl From for ValueParser { fn from(value: std::ops::RangeFull) -> Self { let inner = RangedI64ValueParser::::new().range(value); Self::from(inner) } } /// Create a [`ValueParser`] with [`PossibleValuesParser`] /// /// See [`PossibleValuesParser`] for more flexibility in creating the /// [`PossibleValue`][crate::builder::PossibleValue]s. /// /// # Examples /// /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("color") /// .long("color") /// .value_parser(["always", "auto", "never"]) /// .default_value("auto") /// ); /// /// let m = cmd.try_get_matches_from_mut( /// ["cmd", "--color", "never"] /// ).unwrap(); /// /// let color: &String = m.get_one("color") /// .expect("default"); /// assert_eq!(color, "never"); /// ``` impl From<[P; C]> for ValueParser where P: Into, { fn from(values: [P; C]) -> Self { let inner = PossibleValuesParser::from(values); Self::from(inner) } } /// Create a [`ValueParser`] with [`PossibleValuesParser`] /// /// See [`PossibleValuesParser`] for more flexibility in creating the /// [`PossibleValue`][crate::builder::PossibleValue]s. /// /// # Examples /// /// ```rust /// # use clap_builder as clap; /// let possible = vec!["always", "auto", "never"]; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("color") /// .long("color") /// .value_parser(possible) /// .default_value("auto") /// ); /// /// let m = cmd.try_get_matches_from_mut( /// ["cmd", "--color", "never"] /// ).unwrap(); /// /// let color: &String = m.get_one("color") /// .expect("default"); /// assert_eq!(color, "never"); /// ``` impl

From> for ValueParser where P: Into, { fn from(values: Vec

) -> Self { let inner = PossibleValuesParser::from(values); Self::from(inner) } } impl std::fmt::Debug for ValueParser { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { match &self.0 { ValueParserInner::Bool => f.debug_struct("ValueParser::bool").finish(), ValueParserInner::String => f.debug_struct("ValueParser::string").finish(), ValueParserInner::OsString => f.debug_struct("ValueParser::os_string").finish(), ValueParserInner::PathBuf => f.debug_struct("ValueParser::path_buf").finish(), ValueParserInner::Other(o) => write!(f, "ValueParser::other({:?})", o.type_id()), } } } impl Clone for ValueParser { fn clone(&self) -> Self { Self(match &self.0 { ValueParserInner::Bool => ValueParserInner::Bool, ValueParserInner::String => ValueParserInner::String, ValueParserInner::OsString => ValueParserInner::OsString, ValueParserInner::PathBuf => ValueParserInner::PathBuf, ValueParserInner::Other(o) => ValueParserInner::Other(o.clone_any()), }) } } /// A type-erased wrapper for [`TypedValueParser`]. trait AnyValueParser: Send + Sync + 'static { fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result; fn parse_ref_( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, _source: ValueSource, ) -> Result { self.parse_ref(cmd, arg, value) } fn parse( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: std::ffi::OsString, ) -> Result; fn parse_( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: std::ffi::OsString, _source: ValueSource, ) -> Result { self.parse(cmd, arg, value) } /// Describes the content of `AnyValue` fn type_id(&self) -> AnyValueId; fn possible_values( &self, ) -> Option + '_>>; fn clone_any(&self) -> Box; } impl AnyValueParser for P where T: std::any::Any + Clone + Send + Sync + 'static, P: TypedValueParser, { fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { let value = ok!(TypedValueParser::parse_ref(self, cmd, arg, value)); Ok(AnyValue::new(value)) } fn parse_ref_( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, source: ValueSource, ) -> Result { let value = ok!(TypedValueParser::parse_ref_(self, cmd, arg, value, source)); Ok(AnyValue::new(value)) } fn parse( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: std::ffi::OsString, ) -> Result { let value = ok!(TypedValueParser::parse(self, cmd, arg, value)); Ok(AnyValue::new(value)) } fn parse_( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: std::ffi::OsString, source: ValueSource, ) -> Result { let value = ok!(TypedValueParser::parse_(self, cmd, arg, value, source)); Ok(AnyValue::new(value)) } fn type_id(&self) -> AnyValueId { AnyValueId::of::() } fn possible_values( &self, ) -> Option + '_>> { P::possible_values(self) } fn clone_any(&self) -> Box { Box::new(self.clone()) } } /// Parse/validate argument values /// /// As alternatives to implementing `TypedValueParser`, /// - Use `Fn(&str) -> Result` which implements `TypedValueParser` /// - [`TypedValueParser::map`] or [`TypedValueParser::try_map`] to adapt an existing `TypedValueParser` /// /// See `ValueParserFactory` to register `TypedValueParser::Value` with /// [`value_parser!`][crate::value_parser]. /// /// # Example /// /// ```rust /// # #[cfg(feature = "error-context")] { /// # use clap_builder as clap; /// # use clap::error::ErrorKind; /// # use clap::error::ContextKind; /// # use clap::error::ContextValue; /// #[derive(Clone)] /// struct Custom(u32); /// /// #[derive(Clone)] /// struct CustomValueParser; /// /// impl clap::builder::TypedValueParser for CustomValueParser { /// type Value = Custom; /// /// fn parse_ref( /// &self, /// cmd: &clap::Command, /// arg: Option<&clap::Arg>, /// value: &std::ffi::OsStr, /// ) -> Result { /// let inner = clap::value_parser!(u32); /// let val = inner.parse_ref(cmd, arg, value)?; /// /// const INVALID_VALUE: u32 = 10; /// if val == INVALID_VALUE { /// let mut err = clap::Error::new(ErrorKind::ValueValidation) /// .with_cmd(cmd); /// if let Some(arg) = arg { /// err.insert(ContextKind::InvalidArg, ContextValue::String(arg.to_string())); /// } /// err.insert(ContextKind::InvalidValue, ContextValue::String(INVALID_VALUE.to_string())); /// return Err(err); /// } /// /// Ok(Custom(val)) /// } /// } /// # } /// ``` pub trait TypedValueParser: Clone + Send + Sync + 'static { /// Argument's value type type Value: Send + Sync + Clone; /// Parse the argument value /// /// When `arg` is `None`, an external subcommand value is being parsed. fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result; /// Parse the argument value /// /// When `arg` is `None`, an external subcommand value is being parsed. fn parse_ref_( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, _source: ValueSource, ) -> Result { self.parse_ref(cmd, arg, value) } /// Parse the argument value /// /// When `arg` is `None`, an external subcommand value is being parsed. fn parse( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: std::ffi::OsString, ) -> Result { self.parse_ref(cmd, arg, &value) } /// Parse the argument value /// /// When `arg` is `None`, an external subcommand value is being parsed. fn parse_( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: std::ffi::OsString, _source: ValueSource, ) -> Result { self.parse(cmd, arg, value) } /// Reflect on enumerated value properties /// /// Error checking should not be done with this; it is mostly targeted at user-facing /// applications like errors and completion. fn possible_values( &self, ) -> Option + '_>> { None } /// Adapt a `TypedValueParser` from one value to another /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// # use clap::Command; /// # use clap::Arg; /// # use clap::builder::TypedValueParser as _; /// # use clap::builder::BoolishValueParser; /// let cmd = Command::new("mycmd") /// .arg( /// Arg::new("flag") /// .long("flag") /// .action(clap::ArgAction::SetTrue) /// .value_parser( /// BoolishValueParser::new() /// .map(|b| -> usize { /// if b { 10 } else { 5 } /// }) /// ) /// ); /// /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap(); /// assert!(matches.contains_id("flag")); /// assert_eq!( /// matches.get_one::("flag").copied(), /// Some(10) /// ); /// /// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap(); /// assert!(matches.contains_id("flag")); /// assert_eq!( /// matches.get_one::("flag").copied(), /// Some(5) /// ); /// ``` fn map(self, func: F) -> MapValueParser where T: Send + Sync + Clone, F: Fn(Self::Value) -> T + Clone, { MapValueParser::new(self, func) } /// Adapt a `TypedValueParser` from one value to another /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// # use std::ffi::OsString; /// # use std::ffi::OsStr; /// # use std::path::PathBuf; /// # use std::path::Path; /// # use clap::Command; /// # use clap::Arg; /// # use clap::builder::TypedValueParser as _; /// # use clap::builder::OsStringValueParser; /// let cmd = Command::new("mycmd") /// .arg( /// Arg::new("flag") /// .long("flag") /// .value_parser( /// OsStringValueParser::new() /// .try_map(verify_ext) /// ) /// ); /// /// fn verify_ext(os: OsString) -> Result { /// let path = PathBuf::from(os); /// if path.extension() != Some(OsStr::new("rs")) { /// return Err("only Rust files are supported"); /// } /// Ok(path) /// } /// /// let error = cmd.clone().try_get_matches_from(["mycmd", "--flag", "foo.txt"]).unwrap_err(); /// error.print(); /// /// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "foo.rs"]).unwrap(); /// assert!(matches.contains_id("flag")); /// assert_eq!( /// matches.get_one::("flag").map(|s| s.as_path()), /// Some(Path::new("foo.rs")) /// ); /// ``` fn try_map(self, func: F) -> TryMapValueParser where F: Fn(Self::Value) -> Result + Clone + Send + Sync + 'static, T: Send + Sync + Clone, E: Into>, { TryMapValueParser::new(self, func) } } impl TypedValueParser for F where F: Fn(&str) -> Result + Clone + Send + Sync + 'static, E: Into>, T: Send + Sync + Clone, { type Value = T; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { let value = ok!(value.to_str().ok_or_else(|| { crate::Error::invalid_utf8( cmd, crate::output::Usage::new(cmd).create_usage_with_title(&[]), ) })); let value = ok!((self)(value).map_err(|e| { let arg = arg .map(|a| a.to_string()) .unwrap_or_else(|| "...".to_owned()); crate::Error::value_validation(arg, value.to_owned(), e.into()).with_cmd(cmd) })); Ok(value) } } /// Implementation for [`ValueParser::string`] /// /// Useful for composing new [`TypedValueParser`]s #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub struct StringValueParser {} impl StringValueParser { /// Implementation for [`ValueParser::string`] pub fn new() -> Self { Self {} } } impl TypedValueParser for StringValueParser { type Value = String; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { TypedValueParser::parse(self, cmd, arg, value.to_owned()) } fn parse( &self, cmd: &crate::Command, _arg: Option<&crate::Arg>, value: std::ffi::OsString, ) -> Result { let value = ok!(value.into_string().map_err(|_| { crate::Error::invalid_utf8( cmd, crate::output::Usage::new(cmd).create_usage_with_title(&[]), ) })); Ok(value) } } impl Default for StringValueParser { fn default() -> Self { Self::new() } } /// Implementation for [`ValueParser::os_string`] /// /// Useful for composing new [`TypedValueParser`]s #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub struct OsStringValueParser {} impl OsStringValueParser { /// Implementation for [`ValueParser::os_string`] pub fn new() -> Self { Self {} } } impl TypedValueParser for OsStringValueParser { type Value = std::ffi::OsString; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { TypedValueParser::parse(self, cmd, arg, value.to_owned()) } fn parse( &self, _cmd: &crate::Command, _arg: Option<&crate::Arg>, value: std::ffi::OsString, ) -> Result { Ok(value) } } impl Default for OsStringValueParser { fn default() -> Self { Self::new() } } /// Implementation for [`ValueParser::path_buf`] /// /// Useful for composing new [`TypedValueParser`]s #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub struct PathBufValueParser {} impl PathBufValueParser { /// Implementation for [`ValueParser::path_buf`] pub fn new() -> Self { Self {} } } impl TypedValueParser for PathBufValueParser { type Value = std::path::PathBuf; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { TypedValueParser::parse(self, cmd, arg, value.to_owned()) } fn parse( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: std::ffi::OsString, ) -> Result { if value.is_empty() { return Err(crate::Error::empty_value( cmd, &[], arg.map(ToString::to_string) .unwrap_or_else(|| "...".to_owned()), )); } Ok(Self::Value::from(value)) } } impl Default for PathBufValueParser { fn default() -> Self { Self::new() } } /// Parse an [`ValueEnum`][crate::ValueEnum] value. /// /// See also: /// - [`PossibleValuesParser`] /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// # use std::ffi::OsStr; /// # use clap::ColorChoice; /// # use clap::builder::TypedValueParser; /// # let cmd = clap::Command::new("test"); /// # let arg = None; /// /// // Usage /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("color") /// .value_parser(clap::builder::EnumValueParser::::new()) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "always"]).unwrap(); /// let port: ColorChoice = *m.get_one("color") /// .expect("required"); /// assert_eq!(port, ColorChoice::Always); /// /// // Semantics /// let value_parser = clap::builder::EnumValueParser::::new(); /// // or /// let value_parser = clap::value_parser!(ColorChoice); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err()); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("always")).unwrap(), ColorChoice::Always); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("auto")).unwrap(), ColorChoice::Auto); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("never")).unwrap(), ColorChoice::Never); /// ``` #[derive(Clone, Debug)] pub struct EnumValueParser( std::marker::PhantomData, ); impl EnumValueParser { /// Parse an [`ValueEnum`][crate::ValueEnum] pub fn new() -> Self { let phantom: std::marker::PhantomData = Default::default(); Self(phantom) } } impl TypedValueParser for EnumValueParser { type Value = E; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { let ignore_case = arg.map(|a| a.is_ignore_case_set()).unwrap_or(false); let possible_vals = || { E::value_variants() .iter() .filter_map(|v| v.to_possible_value()) .filter(|v| !v.is_hide_set()) .map(|v| v.get_name().to_owned()) .collect::>() }; let value = ok!(value.to_str().ok_or_else(|| { crate::Error::invalid_value( cmd, value.to_string_lossy().into_owned(), &possible_vals(), arg.map(ToString::to_string) .unwrap_or_else(|| "...".to_owned()), ) })); let value = ok!(E::value_variants() .iter() .find(|v| { v.to_possible_value() .expect("ValueEnum::value_variants contains only values with a corresponding ValueEnum::to_possible_value") .matches(value, ignore_case) }) .ok_or_else(|| { crate::Error::invalid_value( cmd, value.to_owned(), &possible_vals(), arg.map(ToString::to_string) .unwrap_or_else(|| "...".to_owned()), ) })) .clone(); Ok(value) } fn possible_values( &self, ) -> Option + '_>> { Some(Box::new( E::value_variants() .iter() .filter_map(|v| v.to_possible_value()), )) } } impl Default for EnumValueParser { fn default() -> Self { Self::new() } } /// Verify the value is from an enumerated set of [`PossibleValue`][crate::builder::PossibleValue]. /// /// See also: /// - [`EnumValueParser`] for directly supporting [`ValueEnum`][crate::ValueEnum] types /// - [`TypedValueParser::map`] for adapting values to a more specialized type, like an external /// enums that can't implement [`ValueEnum`][crate::ValueEnum] /// /// # Example /// /// Usage: /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("color") /// .value_parser(clap::builder::PossibleValuesParser::new(["always", "auto", "never"])) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "always"]).unwrap(); /// let port: &String = m.get_one("color") /// .expect("required"); /// assert_eq!(port, "always"); /// ``` /// /// Semantics: /// ```rust /// # use clap_builder as clap; /// # use std::ffi::OsStr; /// # use clap::builder::TypedValueParser; /// # let cmd = clap::Command::new("test"); /// # let arg = None; /// let value_parser = clap::builder::PossibleValuesParser::new(["always", "auto", "never"]); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err()); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("always")).unwrap(), "always"); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("auto")).unwrap(), "auto"); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("never")).unwrap(), "never"); /// ``` #[derive(Clone, Debug)] pub struct PossibleValuesParser(Vec); impl PossibleValuesParser { /// Verify the value is from an enumerated set of [`PossibleValue`][crate::builder::PossibleValue]. pub fn new(values: impl Into) -> Self { values.into() } } impl TypedValueParser for PossibleValuesParser { type Value = String; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { TypedValueParser::parse(self, cmd, arg, value.to_owned()) } fn parse( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: std::ffi::OsString, ) -> Result { let value = ok!(value.into_string().map_err(|_| { crate::Error::invalid_utf8( cmd, crate::output::Usage::new(cmd).create_usage_with_title(&[]), ) })); let ignore_case = arg.map(|a| a.is_ignore_case_set()).unwrap_or(false); if self.0.iter().any(|v| v.matches(&value, ignore_case)) { Ok(value) } else { let possible_vals = self .0 .iter() .filter(|v| !v.is_hide_set()) .map(|v| v.get_name().to_owned()) .collect::>(); Err(crate::Error::invalid_value( cmd, value, &possible_vals, arg.map(ToString::to_string) .unwrap_or_else(|| "...".to_owned()), )) } } fn possible_values( &self, ) -> Option + '_>> { Some(Box::new(self.0.iter().cloned())) } } impl From for PossibleValuesParser where I: IntoIterator, T: Into, { fn from(values: I) -> Self { Self(values.into_iter().map(|t| t.into()).collect()) } } /// Parse number that fall within a range of values /// /// **NOTE:** To capture negative values, you will also need to set /// [`Arg::allow_negative_numbers`][crate::Arg::allow_negative_numbers] or /// [`Arg::allow_hyphen_values`][crate::Arg::allow_hyphen_values]. /// /// # Example /// /// Usage: /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("port") /// .long("port") /// .value_parser(clap::value_parser!(u16).range(3000..)) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "3001"]).unwrap(); /// let port: u16 = *m.get_one("port") /// .expect("required"); /// assert_eq!(port, 3001); /// ``` /// /// Semantics: /// ```rust /// # use clap_builder as clap; /// # use std::ffi::OsStr; /// # use clap::builder::TypedValueParser; /// # let cmd = clap::Command::new("test"); /// # let arg = None; /// let value_parser = clap::builder::RangedI64ValueParser::::new().range(-1..200); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-200")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("300")).is_err()); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("-1")).unwrap(), -1); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0")).unwrap(), 0); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50")).unwrap(), 50); /// ``` #[derive(Copy, Clone, Debug)] pub struct RangedI64ValueParser + Clone + Send + Sync = i64> { bounds: (std::ops::Bound, std::ops::Bound), target: std::marker::PhantomData, } impl + Clone + Send + Sync> RangedI64ValueParser { /// Select full range of `i64` pub fn new() -> Self { Self::from(..) } /// Narrow the supported range pub fn range>(mut self, range: B) -> Self { // Consideration: when the user does `value_parser!(u8).range()` // - Avoid programming mistakes by accidentally expanding the range // - Make it convenient to limit the range like with `..10` let start = match range.start_bound() { l @ std::ops::Bound::Included(i) => { debug_assert!( self.bounds.contains(i), "{} must be in {:?}", i, self.bounds ); l.cloned() } l @ std::ops::Bound::Excluded(i) => { debug_assert!( self.bounds.contains(&i.saturating_add(1)), "{} must be in {:?}", i, self.bounds ); l.cloned() } std::ops::Bound::Unbounded => self.bounds.start_bound().cloned(), }; let end = match range.end_bound() { l @ std::ops::Bound::Included(i) => { debug_assert!( self.bounds.contains(i), "{} must be in {:?}", i, self.bounds ); l.cloned() } l @ std::ops::Bound::Excluded(i) => { debug_assert!( self.bounds.contains(&i.saturating_sub(1)), "{} must be in {:?}", i, self.bounds ); l.cloned() } std::ops::Bound::Unbounded => self.bounds.end_bound().cloned(), }; self.bounds = (start, end); self } fn format_bounds(&self) -> String { let mut result = match self.bounds.0 { std::ops::Bound::Included(i) => i.to_string(), std::ops::Bound::Excluded(i) => i.saturating_add(1).to_string(), std::ops::Bound::Unbounded => i64::MIN.to_string(), }; result.push_str(".."); match self.bounds.1 { std::ops::Bound::Included(i) => { result.push('='); result.push_str(&i.to_string()); } std::ops::Bound::Excluded(i) => { result.push_str(&i.to_string()); } std::ops::Bound::Unbounded => { result.push_str(&i64::MAX.to_string()); } } result } } impl + Clone + Send + Sync + 'static> TypedValueParser for RangedI64ValueParser where >::Error: Send + Sync + 'static + std::error::Error + ToString, { type Value = T; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, raw_value: &std::ffi::OsStr, ) -> Result { let value = ok!(raw_value.to_str().ok_or_else(|| { crate::Error::invalid_utf8( cmd, crate::output::Usage::new(cmd).create_usage_with_title(&[]), ) })); let value = ok!(value.parse::().map_err(|err| { let arg = arg .map(|a| a.to_string()) .unwrap_or_else(|| "...".to_owned()); crate::Error::value_validation( arg, raw_value.to_string_lossy().into_owned(), err.into(), ) .with_cmd(cmd) })); if !self.bounds.contains(&value) { let arg = arg .map(|a| a.to_string()) .unwrap_or_else(|| "...".to_owned()); return Err(crate::Error::value_validation( arg, raw_value.to_string_lossy().into_owned(), format!("{} is not in {}", value, self.format_bounds()).into(), ) .with_cmd(cmd)); } let value: Result = value.try_into(); let value = ok!(value.map_err(|err| { let arg = arg .map(|a| a.to_string()) .unwrap_or_else(|| "...".to_owned()); crate::Error::value_validation( arg, raw_value.to_string_lossy().into_owned(), err.into(), ) .with_cmd(cmd) })); Ok(value) } } impl + Clone + Send + Sync, B: RangeBounds> From for RangedI64ValueParser { fn from(range: B) -> Self { Self { bounds: (range.start_bound().cloned(), range.end_bound().cloned()), target: Default::default(), } } } impl + Clone + Send + Sync> Default for RangedI64ValueParser { fn default() -> Self { Self::new() } } /// Parse number that fall within a range of values /// /// # Example /// /// Usage: /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("port") /// .long("port") /// .value_parser(clap::value_parser!(u64).range(3000..)) /// .action(clap::ArgAction::Set) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "--port", "3001"]).unwrap(); /// let port: u64 = *m.get_one("port") /// .expect("required"); /// assert_eq!(port, 3001); /// ``` /// /// Semantics: /// ```rust /// # use clap_builder as clap; /// # use std::ffi::OsStr; /// # use clap::builder::TypedValueParser; /// # let cmd = clap::Command::new("test"); /// # let arg = None; /// let value_parser = clap::builder::RangedU64ValueParser::::new().range(0..200); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-200")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("300")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("-1")).is_err()); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0")).unwrap(), 0); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50")).unwrap(), 50); /// ``` #[derive(Copy, Clone, Debug)] pub struct RangedU64ValueParser = u64> { bounds: (std::ops::Bound, std::ops::Bound), target: std::marker::PhantomData, } impl> RangedU64ValueParser { /// Select full range of `u64` pub fn new() -> Self { Self::from(..) } /// Narrow the supported range pub fn range>(mut self, range: B) -> Self { // Consideration: when the user does `value_parser!(u8).range()` // - Avoid programming mistakes by accidentally expanding the range // - Make it convenient to limit the range like with `..10` let start = match range.start_bound() { l @ std::ops::Bound::Included(i) => { debug_assert!( self.bounds.contains(i), "{} must be in {:?}", i, self.bounds ); l.cloned() } l @ std::ops::Bound::Excluded(i) => { debug_assert!( self.bounds.contains(&i.saturating_add(1)), "{} must be in {:?}", i, self.bounds ); l.cloned() } std::ops::Bound::Unbounded => self.bounds.start_bound().cloned(), }; let end = match range.end_bound() { l @ std::ops::Bound::Included(i) => { debug_assert!( self.bounds.contains(i), "{} must be in {:?}", i, self.bounds ); l.cloned() } l @ std::ops::Bound::Excluded(i) => { debug_assert!( self.bounds.contains(&i.saturating_sub(1)), "{} must be in {:?}", i, self.bounds ); l.cloned() } std::ops::Bound::Unbounded => self.bounds.end_bound().cloned(), }; self.bounds = (start, end); self } fn format_bounds(&self) -> String { let mut result = match self.bounds.0 { std::ops::Bound::Included(i) => i.to_string(), std::ops::Bound::Excluded(i) => i.saturating_add(1).to_string(), std::ops::Bound::Unbounded => u64::MIN.to_string(), }; result.push_str(".."); match self.bounds.1 { std::ops::Bound::Included(i) => { result.push('='); result.push_str(&i.to_string()); } std::ops::Bound::Excluded(i) => { result.push_str(&i.to_string()); } std::ops::Bound::Unbounded => { result.push_str(&u64::MAX.to_string()); } } result } } impl + Clone + Send + Sync + 'static> TypedValueParser for RangedU64ValueParser where >::Error: Send + Sync + 'static + std::error::Error + ToString, { type Value = T; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, raw_value: &std::ffi::OsStr, ) -> Result { let value = ok!(raw_value.to_str().ok_or_else(|| { crate::Error::invalid_utf8( cmd, crate::output::Usage::new(cmd).create_usage_with_title(&[]), ) })); let value = ok!(value.parse::().map_err(|err| { let arg = arg .map(|a| a.to_string()) .unwrap_or_else(|| "...".to_owned()); crate::Error::value_validation( arg, raw_value.to_string_lossy().into_owned(), err.into(), ) .with_cmd(cmd) })); if !self.bounds.contains(&value) { let arg = arg .map(|a| a.to_string()) .unwrap_or_else(|| "...".to_owned()); return Err(crate::Error::value_validation( arg, raw_value.to_string_lossy().into_owned(), format!("{} is not in {}", value, self.format_bounds()).into(), ) .with_cmd(cmd)); } let value: Result = value.try_into(); let value = ok!(value.map_err(|err| { let arg = arg .map(|a| a.to_string()) .unwrap_or_else(|| "...".to_owned()); crate::Error::value_validation( arg, raw_value.to_string_lossy().into_owned(), err.into(), ) .with_cmd(cmd) })); Ok(value) } } impl, B: RangeBounds> From for RangedU64ValueParser { fn from(range: B) -> Self { Self { bounds: (range.start_bound().cloned(), range.end_bound().cloned()), target: Default::default(), } } } impl> Default for RangedU64ValueParser { fn default() -> Self { Self::new() } } /// Implementation for [`ValueParser::bool`] /// /// Useful for composing new [`TypedValueParser`]s #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub struct BoolValueParser {} impl BoolValueParser { /// Implementation for [`ValueParser::bool`] pub fn new() -> Self { Self {} } fn possible_values() -> impl Iterator { ["true", "false"] .iter() .copied() .map(crate::builder::PossibleValue::new) } } impl TypedValueParser for BoolValueParser { type Value = bool; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { let value = if value == std::ffi::OsStr::new("true") { true } else if value == std::ffi::OsStr::new("false") { false } else { // Intentionally showing hidden as we hide all of them let possible_vals = Self::possible_values() .map(|v| v.get_name().to_owned()) .collect::>(); return Err(crate::Error::invalid_value( cmd, value.to_string_lossy().into_owned(), &possible_vals, arg.map(ToString::to_string) .unwrap_or_else(|| "...".to_owned()), )); }; Ok(value) } fn possible_values( &self, ) -> Option + '_>> { Some(Box::new(Self::possible_values())) } } impl Default for BoolValueParser { fn default() -> Self { Self::new() } } /// Parse false-like string values, everything else is `true` /// /// See also: /// - [`ValueParser::bool`] for assuming non-false is true /// - [`BoolishValueParser`] for different human readable bool representations /// /// # Example /// /// Usage: /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("append") /// .value_parser(clap::builder::FalseyValueParser::new()) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "true"]).unwrap(); /// let port: bool = *m.get_one("append") /// .expect("required"); /// assert_eq!(port, true); /// ``` /// /// Semantics: /// ```rust /// # use clap_builder as clap; /// # use std::ffi::OsStr; /// # use clap::builder::TypedValueParser; /// # let cmd = clap::Command::new("test"); /// # let arg = None; /// let value_parser = clap::builder::FalseyValueParser::new(); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).unwrap(), true); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("100")).unwrap(), true); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).unwrap(), false); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("false")).unwrap(), false); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("No")).unwrap(), false); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oFF")).unwrap(), false); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0")).unwrap(), false); /// ``` #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub struct FalseyValueParser {} impl FalseyValueParser { /// Parse false-like string values, everything else is `true` pub fn new() -> Self { Self {} } fn possible_values() -> impl Iterator { crate::util::TRUE_LITERALS .iter() .chain(crate::util::FALSE_LITERALS.iter()) .copied() .map(|l| crate::builder::PossibleValue::new(l).hide(l != "true" && l != "false")) } } impl TypedValueParser for FalseyValueParser { type Value = bool; fn parse_ref( &self, cmd: &crate::Command, _arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { let value = ok!(value.to_str().ok_or_else(|| { crate::Error::invalid_utf8( cmd, crate::output::Usage::new(cmd).create_usage_with_title(&[]), ) })); let value = if value.is_empty() { false } else { crate::util::str_to_bool(value).unwrap_or(true) }; Ok(value) } fn possible_values( &self, ) -> Option + '_>> { Some(Box::new(Self::possible_values())) } } impl Default for FalseyValueParser { fn default() -> Self { Self::new() } } /// Parse bool-like string values, everything else is `true` /// /// See also: /// - [`ValueParser::bool`] for different human readable bool representations /// - [`FalseyValueParser`] for assuming non-false is true /// /// # Example /// /// Usage: /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("append") /// .value_parser(clap::builder::BoolishValueParser::new()) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "true"]).unwrap(); /// let port: bool = *m.get_one("append") /// .expect("required"); /// assert_eq!(port, true); /// ``` /// /// Semantics: /// ```rust /// # use clap_builder as clap; /// # use std::ffi::OsStr; /// # use clap::builder::TypedValueParser; /// # let cmd = clap::Command::new("test"); /// # let arg = None; /// let value_parser = clap::builder::BoolishValueParser::new(); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err()); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("100")).is_err()); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("true")).unwrap(), true); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("Yes")).unwrap(), true); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oN")).unwrap(), true); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("1")).unwrap(), true); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("false")).unwrap(), false); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("No")).unwrap(), false); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("oFF")).unwrap(), false); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("0")).unwrap(), false); /// ``` #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub struct BoolishValueParser {} impl BoolishValueParser { /// Parse bool-like string values, everything else is `true` pub fn new() -> Self { Self {} } fn possible_values() -> impl Iterator { crate::util::TRUE_LITERALS .iter() .chain(crate::util::FALSE_LITERALS.iter()) .copied() .map(|l| crate::builder::PossibleValue::new(l).hide(l != "true" && l != "false")) } } impl TypedValueParser for BoolishValueParser { type Value = bool; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { let value = ok!(value.to_str().ok_or_else(|| { crate::Error::invalid_utf8( cmd, crate::output::Usage::new(cmd).create_usage_with_title(&[]), ) })); let value = ok!(crate::util::str_to_bool(value).ok_or_else(|| { let arg = arg .map(|a| a.to_string()) .unwrap_or_else(|| "...".to_owned()); crate::Error::value_validation(arg, value.to_owned(), "value was not a boolean".into()) .with_cmd(cmd) })); Ok(value) } fn possible_values( &self, ) -> Option + '_>> { Some(Box::new(Self::possible_values())) } } impl Default for BoolishValueParser { fn default() -> Self { Self::new() } } /// Parse non-empty string values /// /// See also: /// - [`ValueParser::string`] /// /// # Example /// /// Usage: /// ```rust /// # use clap_builder as clap; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("append") /// .value_parser(clap::builder::NonEmptyStringValueParser::new()) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "true"]).unwrap(); /// let port: &String = m.get_one("append") /// .expect("required"); /// assert_eq!(port, "true"); /// ``` /// /// Semantics: /// ```rust /// # use clap_builder as clap; /// # use std::ffi::OsStr; /// # use clap::builder::TypedValueParser; /// # let cmd = clap::Command::new("test"); /// # let arg = None; /// let value_parser = clap::builder::NonEmptyStringValueParser::new(); /// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("random")).unwrap(), "random"); /// assert!(value_parser.parse_ref(&cmd, arg, OsStr::new("")).is_err()); /// ``` #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub struct NonEmptyStringValueParser {} impl NonEmptyStringValueParser { /// Parse non-empty string values pub fn new() -> Self { Self {} } } impl TypedValueParser for NonEmptyStringValueParser { type Value = String; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { if value.is_empty() { return Err(crate::Error::empty_value( cmd, &[], arg.map(ToString::to_string) .unwrap_or_else(|| "...".to_owned()), )); } let value = ok!(value.to_str().ok_or_else(|| { crate::Error::invalid_utf8( cmd, crate::output::Usage::new(cmd).create_usage_with_title(&[]), ) })); Ok(value.to_owned()) } } impl Default for NonEmptyStringValueParser { fn default() -> Self { Self::new() } } /// Adapt a `TypedValueParser` from one value to another /// /// See [`TypedValueParser::map`] #[derive(Clone, Debug)] pub struct MapValueParser { parser: P, func: F, } impl MapValueParser where P: TypedValueParser, P::Value: Send + Sync + Clone, F: Fn(P::Value) -> T + Clone, T: Send + Sync + Clone, { fn new(parser: P, func: F) -> Self { Self { parser, func } } } impl TypedValueParser for MapValueParser where P: TypedValueParser, P::Value: Send + Sync + Clone, F: Fn(P::Value) -> T + Clone + Send + Sync + 'static, T: Send + Sync + Clone, { type Value = T; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { let value = ok!(self.parser.parse_ref(cmd, arg, value)); let value = (self.func)(value); Ok(value) } fn parse( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: std::ffi::OsString, ) -> Result { let value = ok!(self.parser.parse(cmd, arg, value)); let value = (self.func)(value); Ok(value) } fn possible_values( &self, ) -> Option + '_>> { self.parser.possible_values() } } /// Adapt a `TypedValueParser` from one value to another /// /// See [`TypedValueParser::try_map`] #[derive(Clone, Debug)] pub struct TryMapValueParser { parser: P, func: F, } impl TryMapValueParser where P: TypedValueParser, P::Value: Send + Sync + Clone, F: Fn(P::Value) -> Result + Clone + Send + Sync + 'static, T: Send + Sync + Clone, E: Into>, { fn new(parser: P, func: F) -> Self { Self { parser, func } } } impl TypedValueParser for TryMapValueParser where P: TypedValueParser, P::Value: Send + Sync + Clone, F: Fn(P::Value) -> Result + Clone + Send + Sync + 'static, T: Send + Sync + Clone, E: Into>, { type Value = T; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { let mid_value = ok!(self.parser.parse_ref(cmd, arg, value)); let value = ok!((self.func)(mid_value).map_err(|e| { let arg = arg .map(|a| a.to_string()) .unwrap_or_else(|| "...".to_owned()); crate::Error::value_validation(arg, value.to_string_lossy().into_owned(), e.into()) .with_cmd(cmd) })); Ok(value) } fn possible_values( &self, ) -> Option + '_>> { self.parser.possible_values() } } /// When encountered, report [ErrorKind::UnknownArgument][crate::error::ErrorKind::UnknownArgument] /// /// Useful to help users migrate, either from old versions or similar tools. /// /// # Examples /// /// ```rust /// # use clap_builder as clap; /// # use clap::Command; /// # use clap::Arg; /// let cmd = Command::new("mycmd") /// .args([ /// Arg::new("current-dir") /// .short('C'), /// Arg::new("current-dir-unknown") /// .long("cwd") /// .aliases(["current-dir", "directory", "working-directory", "root"]) /// .value_parser(clap::builder::UnknownArgumentValueParser::suggest_arg("-C")) /// .hide(true), /// ]); /// /// // Use a supported version of the argument /// let matches = cmd.clone().try_get_matches_from(["mycmd", "-C", ".."]).unwrap(); /// assert!(matches.contains_id("current-dir")); /// assert_eq!( /// matches.get_many::("current-dir").unwrap_or_default().map(|v| v.as_str()).collect::>(), /// vec![".."] /// ); /// /// // Use one of the invalid versions /// let err = cmd.try_get_matches_from(["mycmd", "--cwd", ".."]).unwrap_err(); /// assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument); /// ``` #[derive(Clone, Debug)] pub struct UnknownArgumentValueParser { arg: Option, suggestions: Vec, } impl UnknownArgumentValueParser { /// Suggest an alternative argument pub fn suggest_arg(arg: impl Into) -> Self { Self { arg: Some(arg.into()), suggestions: Default::default(), } } /// Provide a general suggestion pub fn suggest(text: impl Into) -> Self { Self { arg: Default::default(), suggestions: vec![text.into()], } } /// Extend the suggestions pub fn and_suggest(mut self, text: impl Into) -> Self { self.suggestions.push(text.into()); self } } impl TypedValueParser for UnknownArgumentValueParser { type Value = String; fn parse_ref( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, ) -> Result { TypedValueParser::parse_ref_(self, cmd, arg, value, ValueSource::CommandLine) } fn parse_ref_( &self, cmd: &crate::Command, arg: Option<&crate::Arg>, _value: &std::ffi::OsStr, source: ValueSource, ) -> Result { match source { ValueSource::DefaultValue => { TypedValueParser::parse_ref_(&StringValueParser::new(), cmd, arg, _value, source) } ValueSource::EnvVariable | ValueSource::CommandLine => { let arg = match arg { Some(arg) => arg.to_string(), None => "..".to_owned(), }; let err = crate::Error::unknown_argument( cmd, arg, self.arg.as_ref().map(|s| (s.as_str().to_owned(), None)), false, crate::output::Usage::new(cmd).create_usage_with_title(&[]), ); #[cfg(feature = "error-context")] let err = { debug_assert_eq!( err.get(crate::error::ContextKind::Suggested), None, "Assuming `Error::unknown_argument` doesn't apply any `Suggested` so we can without caution" ); err.insert_context_unchecked( crate::error::ContextKind::Suggested, crate::error::ContextValue::StyledStrs(self.suggestions.clone()), ) }; Err(err) } } } } /// Register a type with [value_parser!][crate::value_parser!] /// /// # Example /// /// ```rust /// # use clap_builder as clap; /// #[derive(Copy, Clone, Debug)] /// pub struct Custom(u32); /// /// impl clap::builder::ValueParserFactory for Custom { /// type Parser = CustomValueParser; /// fn value_parser() -> Self::Parser { /// CustomValueParser /// } /// } /// /// #[derive(Clone, Debug)] /// pub struct CustomValueParser; /// impl clap::builder::TypedValueParser for CustomValueParser { /// type Value = Custom; /// /// fn parse_ref( /// &self, /// cmd: &clap::Command, /// arg: Option<&clap::Arg>, /// value: &std::ffi::OsStr, /// ) -> Result { /// let inner = clap::value_parser!(u32); /// let val = inner.parse_ref(cmd, arg, value)?; /// Ok(Custom(val)) /// } /// } /// /// let parser: CustomValueParser = clap::value_parser!(Custom); /// ``` pub trait ValueParserFactory { /// Generated parser, usually [`ValueParser`]. /// /// It should at least be a type that supports `Into`. A non-`ValueParser` type /// allows the caller to do further initialization on the parser. type Parser; /// Create the specified [`Self::Parser`] fn value_parser() -> Self::Parser; } impl ValueParserFactory for String { type Parser = ValueParser; fn value_parser() -> Self::Parser { ValueParser::string() // Default `clap_derive` to optimized implementation } } impl ValueParserFactory for Box { type Parser = MapValueParser Box>; fn value_parser() -> Self::Parser { StringValueParser::new().map(String::into_boxed_str) } } impl ValueParserFactory for std::ffi::OsString { type Parser = ValueParser; fn value_parser() -> Self::Parser { ValueParser::os_string() // Default `clap_derive` to optimized implementation } } impl ValueParserFactory for Box { type Parser = MapValueParser Box>; fn value_parser() -> Self::Parser { OsStringValueParser::new().map(std::ffi::OsString::into_boxed_os_str) } } impl ValueParserFactory for std::path::PathBuf { type Parser = ValueParser; fn value_parser() -> Self::Parser { ValueParser::path_buf() // Default `clap_derive` to optimized implementation } } impl ValueParserFactory for Box { type Parser = MapValueParser Box>; fn value_parser() -> Self::Parser { PathBufValueParser::new().map(std::path::PathBuf::into_boxed_path) } } impl ValueParserFactory for bool { type Parser = ValueParser; fn value_parser() -> Self::Parser { ValueParser::bool() // Default `clap_derive` to optimized implementation } } impl ValueParserFactory for u8 { type Parser = RangedI64ValueParser; fn value_parser() -> Self::Parser { let start: i64 = u8::MIN.into(); let end: i64 = u8::MAX.into(); RangedI64ValueParser::new().range(start..=end) } } impl ValueParserFactory for i8 { type Parser = RangedI64ValueParser; fn value_parser() -> Self::Parser { let start: i64 = i8::MIN.into(); let end: i64 = i8::MAX.into(); RangedI64ValueParser::new().range(start..=end) } } impl ValueParserFactory for u16 { type Parser = RangedI64ValueParser; fn value_parser() -> Self::Parser { let start: i64 = u16::MIN.into(); let end: i64 = u16::MAX.into(); RangedI64ValueParser::new().range(start..=end) } } impl ValueParserFactory for i16 { type Parser = RangedI64ValueParser; fn value_parser() -> Self::Parser { let start: i64 = i16::MIN.into(); let end: i64 = i16::MAX.into(); RangedI64ValueParser::new().range(start..=end) } } impl ValueParserFactory for u32 { type Parser = RangedI64ValueParser; fn value_parser() -> Self::Parser { let start: i64 = u32::MIN.into(); let end: i64 = u32::MAX.into(); RangedI64ValueParser::new().range(start..=end) } } impl ValueParserFactory for i32 { type Parser = RangedI64ValueParser; fn value_parser() -> Self::Parser { let start: i64 = i32::MIN.into(); let end: i64 = i32::MAX.into(); RangedI64ValueParser::new().range(start..=end) } } impl ValueParserFactory for u64 { type Parser = RangedU64ValueParser; fn value_parser() -> Self::Parser { RangedU64ValueParser::new() } } impl ValueParserFactory for i64 { type Parser = RangedI64ValueParser; fn value_parser() -> Self::Parser { RangedI64ValueParser::new() } } impl ValueParserFactory for std::num::Wrapping where T: ValueParserFactory, ::Parser: TypedValueParser, T: Send + Sync + Clone, { type Parser = MapValueParser<::Parser, fn(T) -> std::num::Wrapping>; fn value_parser() -> Self::Parser { T::value_parser().map(std::num::Wrapping) } } impl ValueParserFactory for Box where T: ValueParserFactory, ::Parser: TypedValueParser, T: Send + Sync + Clone, { type Parser = MapValueParser<::Parser, fn(T) -> Box>; fn value_parser() -> Self::Parser { T::value_parser().map(Box::new) } } impl ValueParserFactory for std::sync::Arc where T: ValueParserFactory, ::Parser: TypedValueParser, T: Send + Sync + Clone, { type Parser = MapValueParser<::Parser, fn(T) -> std::sync::Arc>; fn value_parser() -> Self::Parser { T::value_parser().map(std::sync::Arc::new) } } #[doc(hidden)] #[derive(Debug)] pub struct _AutoValueParser(std::marker::PhantomData); impl _AutoValueParser { #[doc(hidden)] #[allow(clippy::new_without_default)] pub fn new() -> Self { Self(Default::default()) } } /// Unstable [`ValueParser`] /// /// Implementation may change to more specific instance in the future #[doc(hidden)] #[derive(Debug)] pub struct _AnonymousValueParser(ValueParser); #[doc(hidden)] pub mod via_prelude { use super::*; #[doc(hidden)] pub trait _ValueParserViaFactory: private::_ValueParserViaFactorySealed { type Parser; fn value_parser(&self) -> Self::Parser; } impl _ValueParserViaFactory for &&&&&&_AutoValueParser

{ type Parser = P::Parser; fn value_parser(&self) -> Self::Parser { P::value_parser() } } #[doc(hidden)] pub trait _ValueParserViaValueEnum: private::_ValueParserViaValueEnumSealed { type Output; fn value_parser(&self) -> Self::Output; } impl _ValueParserViaValueEnum for &&&&&_AutoValueParser { type Output = EnumValueParser; fn value_parser(&self) -> Self::Output { EnumValueParser::::new() } } #[doc(hidden)] pub trait _ValueParserViaFromOsString: private::_ValueParserViaFromOsStringSealed { fn value_parser(&self) -> _AnonymousValueParser; } impl _ValueParserViaFromOsString for &&&&_AutoValueParser where FromOsString: From + std::any::Any + Clone + Send + Sync + 'static, { fn value_parser(&self) -> _AnonymousValueParser { _AnonymousValueParser( OsStringValueParser::new() .map(|s| FromOsString::from(s)) .into(), ) } } #[doc(hidden)] pub trait _ValueParserViaFromOsStr: private::_ValueParserViaFromOsStrSealed { fn value_parser(&self) -> _AnonymousValueParser; } impl _ValueParserViaFromOsStr for &&&_AutoValueParser where FromOsStr: for<'s> From<&'s std::ffi::OsStr> + std::any::Any + Clone + Send + Sync + 'static, { fn value_parser(&self) -> _AnonymousValueParser { _AnonymousValueParser( OsStringValueParser::new() .map(|s| FromOsStr::from(&s)) .into(), ) } } #[doc(hidden)] pub trait _ValueParserViaFromString: private::_ValueParserViaFromStringSealed { fn value_parser(&self) -> _AnonymousValueParser; } impl _ValueParserViaFromString for &&_AutoValueParser where FromString: From + std::any::Any + Clone + Send + Sync + 'static, { fn value_parser(&self) -> _AnonymousValueParser { _AnonymousValueParser(StringValueParser::new().map(|s| FromString::from(s)).into()) } } #[doc(hidden)] pub trait _ValueParserViaFromStr: private::_ValueParserViaFromStrSealed { fn value_parser(&self) -> _AnonymousValueParser; } impl _ValueParserViaFromStr for &_AutoValueParser where FromStr: for<'s> From<&'s str> + std::any::Any + Clone + Send + Sync + 'static, { fn value_parser(&self) -> _AnonymousValueParser { _AnonymousValueParser(StringValueParser::new().map(|s| FromStr::from(&s)).into()) } } #[doc(hidden)] pub trait _ValueParserViaParse: private::_ValueParserViaParseSealed { fn value_parser(&self) -> _AnonymousValueParser; } impl _ValueParserViaParse for _AutoValueParser where Parse: std::str::FromStr + std::any::Any + Clone + Send + Sync + 'static, ::Err: Into>, { fn value_parser(&self) -> _AnonymousValueParser { let func: fn(&str) -> Result::Err> = Parse::from_str; _AnonymousValueParser(ValueParser::new(func)) } } } /// Select a [`ValueParser`] implementation from the intended type /// /// Supported types /// - [`ValueParserFactory` types][ValueParserFactory], including /// - [Native types][ValueParser]: `bool`, `String`, `OsString`, `PathBuf` /// - [Ranged numeric types][RangedI64ValueParser]: `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64` /// - [`ValueEnum` types][crate::ValueEnum] /// - [`From` types][std::convert::From] and [`From<&OsStr>` types][std::convert::From] /// - [`From` types][std::convert::From] and [`From<&str>` types][std::convert::From] /// - [`FromStr` types][std::str::FromStr], including usize, isize /// /// # Example /// /// Usage: /// ```rust /// # use clap_builder as clap; /// # use std::path::PathBuf; /// # use std::path::Path; /// let mut cmd = clap::Command::new("raw") /// .arg( /// clap::Arg::new("output") /// .value_parser(clap::value_parser!(PathBuf)) /// .required(true) /// ); /// /// let m = cmd.try_get_matches_from_mut(["cmd", "file.txt"]).unwrap(); /// let port: &PathBuf = m.get_one("output") /// .expect("required"); /// assert_eq!(port, Path::new("file.txt")); /// ``` /// /// Example mappings: /// ```rust /// # use clap_builder as clap; /// # use clap::ColorChoice; /// // Built-in types /// let parser = clap::value_parser!(String); /// assert_eq!(format!("{parser:?}"), "ValueParser::string"); /// let parser = clap::value_parser!(std::ffi::OsString); /// assert_eq!(format!("{parser:?}"), "ValueParser::os_string"); /// let parser = clap::value_parser!(std::path::PathBuf); /// assert_eq!(format!("{parser:?}"), "ValueParser::path_buf"); /// clap::value_parser!(u16).range(3000..); /// clap::value_parser!(u64).range(3000..); /// /// // FromStr types /// let parser = clap::value_parser!(usize); /// assert_eq!(format!("{parser:?}"), "_AnonymousValueParser(ValueParser::other(usize))"); /// /// // ValueEnum types /// clap::value_parser!(ColorChoice); /// ``` #[macro_export] macro_rules! value_parser { ($name:ty) => {{ use $crate::builder::via_prelude::*; let auto = $crate::builder::_AutoValueParser::<$name>::new(); (&&&&&&auto).value_parser() }}; } mod private { use super::*; // Prefer these so `clap_derive` defaults to optimized implementations pub trait _ValueParserViaSelfSealed {} impl> _ValueParserViaSelfSealed for &&&&&&&_AutoValueParser

{} pub trait _ValueParserViaFactorySealed {} impl _ValueParserViaFactorySealed for &&&&&&_AutoValueParser

{} pub trait _ValueParserViaValueEnumSealed {} impl _ValueParserViaValueEnumSealed for &&&&&_AutoValueParser {} pub trait _ValueParserViaFromOsStringSealed {} impl _ValueParserViaFromOsStringSealed for &&&&_AutoValueParser where FromOsString: From + std::any::Any + Send + Sync + 'static { } pub trait _ValueParserViaFromOsStrSealed {} impl _ValueParserViaFromOsStrSealed for &&&_AutoValueParser where FromOsStr: for<'s> From<&'s std::ffi::OsStr> + std::any::Any + Send + Sync + 'static { } pub trait _ValueParserViaFromStringSealed {} impl _ValueParserViaFromStringSealed for &&_AutoValueParser where FromString: From + std::any::Any + Send + Sync + 'static { } pub trait _ValueParserViaFromStrSealed {} impl _ValueParserViaFromStrSealed for &_AutoValueParser where FromStr: for<'s> From<&'s str> + std::any::Any + Send + Sync + 'static { } pub trait _ValueParserViaParseSealed {} impl _ValueParserViaParseSealed for _AutoValueParser where Parse: std::str::FromStr + std::any::Any + Send + Sync + 'static, ::Err: Into>, { } } #[cfg(test)] mod test { use super::*; #[test] fn ensure_typed_applies_to_parse() { fn parse(_: &str) -> Result { Ok(10) } let cmd = crate::Command::new("cmd"); let arg = None; assert_eq!( TypedValueParser::parse_ref(&parse, &cmd, arg, std::ffi::OsStr::new("foo")).unwrap(), 10 ); } }