diff options
Diffstat (limited to 'vendor/clap_builder/src/builder/value_parser.rs')
-rw-r--r-- | vendor/clap_builder/src/builder/value_parser.rs | 2712 |
1 files changed, 0 insertions, 2712 deletions
diff --git a/vendor/clap_builder/src/builder/value_parser.rs b/vendor/clap_builder/src/builder/value_parser.rs deleted file mode 100644 index 1f0ef92..0000000 --- a/vendor/clap_builder/src/builder/value_parser.rs +++ /dev/null @@ -1,2712 +0,0 @@ -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<dyn AnyValueParser>), -} - -impl ValueParser { - /// Custom parser for argument values - /// - /// Pre-existing [`TypedValueParser`] implementations include: - /// - `Fn(&str) -> Result<T, E>` - /// - [`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<String>); - /// fn parse_env_var(env: &str) -> Result<EnvVar, std::io::Error> { - /// 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<P>(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<AnyValue, crate::Error> { - 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<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - 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<P> From<P> 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<std::ops::Range<i64>> for ValueParser { - fn from(value: std::ops::Range<i64>) -> Self { - let inner = RangedI64ValueParser::<i64>::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<std::ops::RangeInclusive<i64>> for ValueParser { - fn from(value: std::ops::RangeInclusive<i64>) -> Self { - let inner = RangedI64ValueParser::<i64>::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<std::ops::RangeFrom<i64>> for ValueParser { - fn from(value: std::ops::RangeFrom<i64>) -> Self { - let inner = RangedI64ValueParser::<i64>::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<std::ops::RangeTo<i64>> for ValueParser { - fn from(value: std::ops::RangeTo<i64>) -> Self { - let inner = RangedI64ValueParser::<i64>::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<std::ops::RangeToInclusive<i64>> for ValueParser { - fn from(value: std::ops::RangeToInclusive<i64>) -> Self { - let inner = RangedI64ValueParser::<i64>::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<std::ops::RangeFull> for ValueParser { - fn from(value: std::ops::RangeFull) -> Self { - let inner = RangedI64ValueParser::<i64>::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<P, const C: usize> From<[P; C]> for ValueParser -where - P: Into<super::PossibleValue>, -{ - 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<P> From<Vec<P>> for ValueParser -where - P: Into<super::PossibleValue>, -{ - fn from(values: Vec<P>) -> 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<AnyValue, crate::Error>; - - fn parse_ref_( - &self, - cmd: &crate::Command, - arg: Option<&crate::Arg>, - value: &std::ffi::OsStr, - _source: ValueSource, - ) -> Result<AnyValue, crate::Error> { - self.parse_ref(cmd, arg, value) - } - - fn parse( - &self, - cmd: &crate::Command, - arg: Option<&crate::Arg>, - value: std::ffi::OsString, - ) -> Result<AnyValue, crate::Error>; - - fn parse_( - &self, - cmd: &crate::Command, - arg: Option<&crate::Arg>, - value: std::ffi::OsString, - _source: ValueSource, - ) -> Result<AnyValue, crate::Error> { - self.parse(cmd, arg, value) - } - - /// Describes the content of `AnyValue` - fn type_id(&self) -> AnyValueId; - - fn possible_values( - &self, - ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>>; - - fn clone_any(&self) -> Box<dyn AnyValueParser>; -} - -impl<T, P> AnyValueParser for P -where - T: std::any::Any + Clone + Send + Sync + 'static, - P: TypedValueParser<Value = T>, -{ - fn parse_ref( - &self, - cmd: &crate::Command, - arg: Option<&crate::Arg>, - value: &std::ffi::OsStr, - ) -> Result<AnyValue, crate::Error> { - 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<AnyValue, crate::Error> { - 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<AnyValue, crate::Error> { - 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<AnyValue, crate::Error> { - let value = ok!(TypedValueParser::parse_(self, cmd, arg, value, source)); - Ok(AnyValue::new(value)) - } - - fn type_id(&self) -> AnyValueId { - AnyValueId::of::<T>() - } - - fn possible_values( - &self, - ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - P::possible_values(self) - } - - fn clone_any(&self) -> Box<dyn AnyValueParser> { - Box::new(self.clone()) - } -} - -/// Parse/validate argument values -/// -/// As alternatives to implementing `TypedValueParser`, -/// - Use `Fn(&str) -> Result<T, E>` 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<Self::Value, clap::Error> { -/// 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<Self::Value, crate::Error>; - - /// 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::Value, crate::Error> { - 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::Value, crate::Error> { - 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::Value, crate::Error> { - 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<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - 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::<usize>("flag").copied(), - /// Some(10) - /// ); - /// - /// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap(); - /// assert!(matches.contains_id("flag")); - /// assert_eq!( - /// matches.get_one::<usize>("flag").copied(), - /// Some(5) - /// ); - /// ``` - fn map<T, F>(self, func: F) -> MapValueParser<Self, F> - 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<PathBuf, &'static str> { - /// 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::<PathBuf>("flag").map(|s| s.as_path()), - /// Some(Path::new("foo.rs")) - /// ); - /// ``` - fn try_map<T, E, F>(self, func: F) -> TryMapValueParser<Self, F> - where - F: Fn(Self::Value) -> Result<T, E> + Clone + Send + Sync + 'static, - T: Send + Sync + Clone, - E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, - { - TryMapValueParser::new(self, func) - } -} - -impl<F, T, E> TypedValueParser for F -where - F: Fn(&str) -> Result<T, E> + Clone + Send + Sync + 'static, - E: Into<Box<dyn std::error::Error + 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<Self::Value, crate::Error> { - 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<Self::Value, crate::Error> { - TypedValueParser::parse(self, cmd, arg, value.to_owned()) - } - - fn parse( - &self, - cmd: &crate::Command, - _arg: Option<&crate::Arg>, - value: std::ffi::OsString, - ) -> Result<Self::Value, crate::Error> { - 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<Self::Value, crate::Error> { - TypedValueParser::parse(self, cmd, arg, value.to_owned()) - } - - fn parse( - &self, - _cmd: &crate::Command, - _arg: Option<&crate::Arg>, - value: std::ffi::OsString, - ) -> Result<Self::Value, crate::Error> { - 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<Self::Value, crate::Error> { - TypedValueParser::parse(self, cmd, arg, value.to_owned()) - } - - fn parse( - &self, - cmd: &crate::Command, - arg: Option<&crate::Arg>, - value: std::ffi::OsString, - ) -> Result<Self::Value, crate::Error> { - 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::<ColorChoice>::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::<ColorChoice>::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<E: crate::ValueEnum + Clone + Send + Sync + 'static>( - std::marker::PhantomData<E>, -); - -impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> EnumValueParser<E> { - /// Parse an [`ValueEnum`][crate::ValueEnum] - pub fn new() -> Self { - let phantom: std::marker::PhantomData<E> = Default::default(); - Self(phantom) - } -} - -impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> TypedValueParser for EnumValueParser<E> { - type Value = E; - - fn parse_ref( - &self, - cmd: &crate::Command, - arg: Option<&crate::Arg>, - value: &std::ffi::OsStr, - ) -> Result<Self::Value, crate::Error> { - 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::<Vec<_>>() - }; - - 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<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - Some(Box::new( - E::value_variants() - .iter() - .filter_map(|v| v.to_possible_value()), - )) - } -} - -impl<E: crate::ValueEnum + Clone + Send + Sync + 'static> Default for EnumValueParser<E> { - 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<super::PossibleValue>); - -impl PossibleValuesParser { - /// Verify the value is from an enumerated set of [`PossibleValue`][crate::builder::PossibleValue]. - pub fn new(values: impl Into<PossibleValuesParser>) -> 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<Self::Value, crate::Error> { - TypedValueParser::parse(self, cmd, arg, value.to_owned()) - } - - fn parse( - &self, - cmd: &crate::Command, - arg: Option<&crate::Arg>, - value: std::ffi::OsString, - ) -> Result<String, crate::Error> { - 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::<Vec<_>>(); - - Err(crate::Error::invalid_value( - cmd, - value, - &possible_vals, - arg.map(ToString::to_string) - .unwrap_or_else(|| "...".to_owned()), - )) - } - } - - fn possible_values( - &self, - ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - Some(Box::new(self.0.iter().cloned())) - } -} - -impl<I, T> From<I> for PossibleValuesParser -where - I: IntoIterator<Item = T>, - T: Into<super::PossibleValue>, -{ - 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::<i32>::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<T: std::convert::TryFrom<i64> + Clone + Send + Sync = i64> { - bounds: (std::ops::Bound<i64>, std::ops::Bound<i64>), - target: std::marker::PhantomData<T>, -} - -impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync> RangedI64ValueParser<T> { - /// Select full range of `i64` - pub fn new() -> Self { - Self::from(..) - } - - /// Narrow the supported range - pub fn range<B: RangeBounds<i64>>(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<T: std::convert::TryFrom<i64> + Clone + Send + Sync + 'static> TypedValueParser - for RangedI64ValueParser<T> -where - <T as std::convert::TryFrom<i64>>::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<Self::Value, crate::Error> { - 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::<i64>().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<Self::Value, _> = 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<T: std::convert::TryFrom<i64> + Clone + Send + Sync, B: RangeBounds<i64>> From<B> - for RangedI64ValueParser<T> -{ - fn from(range: B) -> Self { - Self { - bounds: (range.start_bound().cloned(), range.end_bound().cloned()), - target: Default::default(), - } - } -} - -impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync> Default for RangedI64ValueParser<T> { - 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::<u32>::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<T: std::convert::TryFrom<u64> = u64> { - bounds: (std::ops::Bound<u64>, std::ops::Bound<u64>), - target: std::marker::PhantomData<T>, -} - -impl<T: std::convert::TryFrom<u64>> RangedU64ValueParser<T> { - /// Select full range of `u64` - pub fn new() -> Self { - Self::from(..) - } - - /// Narrow the supported range - pub fn range<B: RangeBounds<u64>>(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<T: std::convert::TryFrom<u64> + Clone + Send + Sync + 'static> TypedValueParser - for RangedU64ValueParser<T> -where - <T as std::convert::TryFrom<u64>>::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<Self::Value, crate::Error> { - 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::<u64>().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<Self::Value, _> = 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<T: std::convert::TryFrom<u64>, B: RangeBounds<u64>> From<B> for RangedU64ValueParser<T> { - fn from(range: B) -> Self { - Self { - bounds: (range.start_bound().cloned(), range.end_bound().cloned()), - target: Default::default(), - } - } -} - -impl<T: std::convert::TryFrom<u64>> Default for RangedU64ValueParser<T> { - 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<Item = crate::builder::PossibleValue> { - ["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<Self::Value, crate::Error> { - 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::<Vec<_>>(); - - 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<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - 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<Item = crate::builder::PossibleValue> { - 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<Self::Value, crate::Error> { - 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<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - 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<Item = crate::builder::PossibleValue> { - 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<Self::Value, crate::Error> { - 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<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - 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<Self::Value, crate::Error> { - 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<P, F> { - parser: P, - func: F, -} - -impl<P, F, T> MapValueParser<P, F> -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<P, F, T> TypedValueParser for MapValueParser<P, F> -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<Self::Value, crate::Error> { - 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<Self::Value, crate::Error> { - let value = ok!(self.parser.parse(cmd, arg, value)); - let value = (self.func)(value); - Ok(value) - } - - fn possible_values( - &self, - ) -> Option<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - self.parser.possible_values() - } -} - -/// Adapt a `TypedValueParser` from one value to another -/// -/// See [`TypedValueParser::try_map`] -#[derive(Clone, Debug)] -pub struct TryMapValueParser<P, F> { - parser: P, - func: F, -} - -impl<P, F, T, E> TryMapValueParser<P, F> -where - P: TypedValueParser, - P::Value: Send + Sync + Clone, - F: Fn(P::Value) -> Result<T, E> + Clone + Send + Sync + 'static, - T: Send + Sync + Clone, - E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, -{ - fn new(parser: P, func: F) -> Self { - Self { parser, func } - } -} - -impl<P, F, T, E> TypedValueParser for TryMapValueParser<P, F> -where - P: TypedValueParser, - P::Value: Send + Sync + Clone, - F: Fn(P::Value) -> Result<T, E> + Clone + Send + Sync + 'static, - T: Send + Sync + Clone, - E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, -{ - type Value = T; - - fn parse_ref( - &self, - cmd: &crate::Command, - arg: Option<&crate::Arg>, - value: &std::ffi::OsStr, - ) -> Result<Self::Value, crate::Error> { - 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<Box<dyn Iterator<Item = crate::builder::PossibleValue> + '_>> { - 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::<String>("current-dir").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(), -/// 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<Str>, - suggestions: Vec<StyledStr>, -} - -impl UnknownArgumentValueParser { - /// Suggest an alternative argument - pub fn suggest_arg(arg: impl Into<Str>) -> Self { - Self { - arg: Some(arg.into()), - suggestions: Default::default(), - } - } - - /// Provide a general suggestion - pub fn suggest(text: impl Into<StyledStr>) -> Self { - Self { - arg: Default::default(), - suggestions: vec![text.into()], - } - } - - /// Extend the suggestions - pub fn and_suggest(mut self, text: impl Into<StyledStr>) -> 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<Self::Value, crate::Error> { - 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<Self::Value, crate::Error> { - 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<Self::Value, clap::Error> { -/// 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<ValueParser>`. 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<str> { - type Parser = MapValueParser<StringValueParser, fn(String) -> Box<str>>; - 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<std::ffi::OsStr> { - type Parser = - MapValueParser<OsStringValueParser, fn(std::ffi::OsString) -> Box<std::ffi::OsStr>>; - 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<std::path::Path> { - type Parser = - MapValueParser<PathBufValueParser, fn(std::path::PathBuf) -> Box<std::path::Path>>; - 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<u8>; - 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<i8>; - 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<u16>; - 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<i16>; - 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<u32>; - 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<i32>; - 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<u64>; - fn value_parser() -> Self::Parser { - RangedU64ValueParser::new() - } -} -impl ValueParserFactory for i64 { - type Parser = RangedI64ValueParser<i64>; - fn value_parser() -> Self::Parser { - RangedI64ValueParser::new() - } -} -impl<T> ValueParserFactory for std::num::Wrapping<T> -where - T: ValueParserFactory, - <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, - T: Send + Sync + Clone, -{ - type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> std::num::Wrapping<T>>; - fn value_parser() -> Self::Parser { - T::value_parser().map(std::num::Wrapping) - } -} -impl<T> ValueParserFactory for Box<T> -where - T: ValueParserFactory, - <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, - T: Send + Sync + Clone, -{ - type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> Box<T>>; - fn value_parser() -> Self::Parser { - T::value_parser().map(Box::new) - } -} -impl<T> ValueParserFactory for std::sync::Arc<T> -where - T: ValueParserFactory, - <T as ValueParserFactory>::Parser: TypedValueParser<Value = T>, - T: Send + Sync + Clone, -{ - type Parser = MapValueParser<<T as ValueParserFactory>::Parser, fn(T) -> std::sync::Arc<T>>; - fn value_parser() -> Self::Parser { - T::value_parser().map(std::sync::Arc::new) - } -} - -#[doc(hidden)] -#[derive(Debug)] -pub struct _AutoValueParser<T>(std::marker::PhantomData<T>); - -impl<T> _AutoValueParser<T> { - #[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<P: ValueParserFactory> _ValueParserViaFactory for &&&&&&_AutoValueParser<P> { - 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<E: crate::ValueEnum + Clone + Send + Sync + 'static> _ValueParserViaValueEnum - for &&&&&_AutoValueParser<E> - { - type Output = EnumValueParser<E>; - - fn value_parser(&self) -> Self::Output { - EnumValueParser::<E>::new() - } - } - - #[doc(hidden)] - pub trait _ValueParserViaFromOsString: private::_ValueParserViaFromOsStringSealed { - fn value_parser(&self) -> _AnonymousValueParser; - } - impl<FromOsString> _ValueParserViaFromOsString for &&&&_AutoValueParser<FromOsString> - where - FromOsString: From<std::ffi::OsString> + 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<FromOsStr> _ValueParserViaFromOsStr for &&&_AutoValueParser<FromOsStr> - 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<FromString> _ValueParserViaFromString for &&_AutoValueParser<FromString> - where - FromString: From<String> + 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<FromStr> _ValueParserViaFromStr for &_AutoValueParser<FromStr> - 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<Parse> _ValueParserViaParse for _AutoValueParser<Parse> - where - Parse: std::str::FromStr + std::any::Any + Clone + Send + Sync + 'static, - <Parse as std::str::FromStr>::Err: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, - { - fn value_parser(&self) -> _AnonymousValueParser { - let func: fn(&str) -> Result<Parse, <Parse as std::str::FromStr>::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<OsString>` types][std::convert::From] and [`From<&OsStr>` types][std::convert::From] -/// - [`From<String>` 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<P: Into<ValueParser>> _ValueParserViaSelfSealed for &&&&&&&_AutoValueParser<P> {} - - pub trait _ValueParserViaFactorySealed {} - impl<P: ValueParserFactory> _ValueParserViaFactorySealed for &&&&&&_AutoValueParser<P> {} - - pub trait _ValueParserViaValueEnumSealed {} - impl<E: crate::ValueEnum> _ValueParserViaValueEnumSealed for &&&&&_AutoValueParser<E> {} - - pub trait _ValueParserViaFromOsStringSealed {} - impl<FromOsString> _ValueParserViaFromOsStringSealed for &&&&_AutoValueParser<FromOsString> where - FromOsString: From<std::ffi::OsString> + std::any::Any + Send + Sync + 'static - { - } - - pub trait _ValueParserViaFromOsStrSealed {} - impl<FromOsStr> _ValueParserViaFromOsStrSealed for &&&_AutoValueParser<FromOsStr> where - FromOsStr: for<'s> From<&'s std::ffi::OsStr> + std::any::Any + Send + Sync + 'static - { - } - - pub trait _ValueParserViaFromStringSealed {} - impl<FromString> _ValueParserViaFromStringSealed for &&_AutoValueParser<FromString> where - FromString: From<String> + std::any::Any + Send + Sync + 'static - { - } - - pub trait _ValueParserViaFromStrSealed {} - impl<FromStr> _ValueParserViaFromStrSealed for &_AutoValueParser<FromStr> where - FromStr: for<'s> From<&'s str> + std::any::Any + Send + Sync + 'static - { - } - - pub trait _ValueParserViaParseSealed {} - impl<Parse> _ValueParserViaParseSealed for _AutoValueParser<Parse> - where - Parse: std::str::FromStr + std::any::Any + Send + Sync + 'static, - <Parse as std::str::FromStr>::Err: Into<Box<dyn std::error::Error + Send + Sync + 'static>>, - { - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn ensure_typed_applies_to_parse() { - fn parse(_: &str) -> Result<usize, std::io::Error> { - 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 - ); - } -} |