diff --git a/examples/derive_ref/README.md b/examples/derive_ref/README.md index b3e16690222..7beef4d2d24 100644 --- a/examples/derive_ref/README.md +++ b/examples/derive_ref/README.md @@ -175,6 +175,7 @@ These correspond to a `clap::Arg`. - When not present: case-converted field name is used - `value_parser [= ]`: `clap::Arg::value_parser` - When not present: will auto-select an implementation based on the field type + - To register a custom type's `ValueParser`, implement `ValueParserFactory` - `help = `: `clap::Arg::help` - When not present: [Doc comment summary](#doc-comments) - `long_help = `: `clap::Arg::long_help` diff --git a/src/builder/mod.rs b/src/builder/mod.rs index 5cd8e154bcf..9b009ea31fe 100644 --- a/src/builder/mod.rs +++ b/src/builder/mod.rs @@ -45,6 +45,7 @@ pub use value_parser::RangedI64ValueParser; pub use value_parser::StringValueParser; pub use value_parser::TypedValueParser; pub use value_parser::ValueParser; +pub use value_parser::ValueParserFactory; #[allow(deprecated)] pub use command::App; diff --git a/src/builder/value_parser.rs b/src/builder/value_parser.rs index 8ba8742f3d2..01aeef57f6f 100644 --- a/src/builder/value_parser.rs +++ b/src/builder/value_parser.rs @@ -1567,6 +1567,127 @@ impl Default for NonEmptyStringValueParser { } } +/// Register a type with [value_parser!][crate::value_parser!] +/// +/// # Example +/// +/// ```rust +/// pub struct Custom(u32); +/// +/// impl clap::builder::ValueParserFactory for Custom { +/// type Parser = CustomValueParser; +/// fn value_parser() -> Self::Parser { +/// CustomValueParser +/// } +/// } +/// +/// 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() + } +} +impl ValueParserFactory for std::ffi::OsString { + type Parser = ValueParser; + fn value_parser() -> Self::Parser { + ValueParser::os_string() + } +} +impl ValueParserFactory for std::path::PathBuf { + type Parser = ValueParser; + fn value_parser() -> Self::Parser { + ValueParser::path_buf() + } +} +impl ValueParserFactory for bool { + type Parser = ValueParser; + fn value_parser() -> Self::Parser { + ValueParser::bool() + } +} +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 i64 { + type Parser = RangedI64ValueParser; + fn value_parser() -> Self::Parser { + RangedI64ValueParser::new() + } +} + #[doc(hidden)] #[derive(Debug)] pub struct AutoValueParser(std::marker::PhantomData); @@ -1584,86 +1705,14 @@ pub mod via_prelude { use super::*; #[doc(hidden)] - pub trait ValueParserViaBuiltIn: private::ValueParserViaBuiltInSealed { + pub trait ValueParserViaFactory: private::ValueParserViaFactorySealed { type Parser; fn value_parser(&self) -> Self::Parser; } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = ValueParser; - fn value_parser(&self) -> Self::Parser { - ValueParser::string() - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = ValueParser; - fn value_parser(&self) -> Self::Parser { - ValueParser::os_string() - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = ValueParser; - fn value_parser(&self) -> Self::Parser { - ValueParser::path_buf() - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = ValueParser; - fn value_parser(&self) -> Self::Parser { - ValueParser::bool() - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = RangedI64ValueParser; - fn value_parser(&self) -> Self::Parser { - let start: i64 = u8::MIN.into(); - let end: i64 = u8::MAX.into(); - RangedI64ValueParser::new().range(start..=end) - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = RangedI64ValueParser; + impl ValueParserViaFactory for &&AutoValueParser

{ + type Parser = P::Parser; fn value_parser(&self) -> Self::Parser { - let start: i64 = i8::MIN.into(); - let end: i64 = i8::MAX.into(); - RangedI64ValueParser::new().range(start..=end) - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = RangedI64ValueParser; - fn value_parser(&self) -> Self::Parser { - let start: i64 = u16::MIN.into(); - let end: i64 = u16::MAX.into(); - RangedI64ValueParser::new().range(start..=end) - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = RangedI64ValueParser; - fn value_parser(&self) -> Self::Parser { - let start: i64 = i16::MIN.into(); - let end: i64 = i16::MAX.into(); - RangedI64ValueParser::new().range(start..=end) - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = RangedI64ValueParser; - fn value_parser(&self) -> Self::Parser { - let start: i64 = u32::MIN.into(); - let end: i64 = u32::MAX.into(); - RangedI64ValueParser::new().range(start..=end) - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = RangedI64ValueParser; - fn value_parser(&self) -> Self::Parser { - let start: i64 = i32::MIN.into(); - let end: i64 = i32::MAX.into(); - RangedI64ValueParser::new().range(start..=end) - } - } - impl ValueParserViaBuiltIn for &&AutoValueParser { - type Parser = RangedI64ValueParser; - fn value_parser(&self) -> Self::Parser { - RangedI64ValueParser::new() + P::value_parser() } } @@ -1703,6 +1752,8 @@ pub mod via_prelude { /// Select a [`ValueParser`] implementation from the intended type /// +/// To register a custom type with this macro, implement [`ValueParserFactory`]. +/// /// # Example /// /// Usage: @@ -1784,18 +1835,8 @@ mod private { pub trait ValueParserViaSelfSealed {} impl> ValueParserViaSelfSealed for &&&AutoValueParser

{} - pub trait ValueParserViaBuiltInSealed {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} - impl ValueParserViaBuiltInSealed for &&AutoValueParser {} + pub trait ValueParserViaFactorySealed {} + impl ValueParserViaFactorySealed for &&AutoValueParser

{} pub trait ValueParserViaArgEnumSealed {} impl ValueParserViaArgEnumSealed for &AutoValueParser {}