Skip to content

Commit

Permalink
Merge pull request #3755 from epage/factory
Browse files Browse the repository at this point in the history
feat(parser): Allow people to plug into 'value_parser' macro
  • Loading branch information
epage committed May 25, 2022
2 parents 999647f + fcdd317 commit 52c1841
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 88 deletions.
1 change: 1 addition & 0 deletions examples/derive_ref/README.md
Expand Up @@ -175,6 +175,7 @@ These correspond to a `clap::Arg`.
- When not present: case-converted field name is used
- `value_parser [= <expr>]`: `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 = <expr>`: `clap::Arg::help`
- When not present: [Doc comment summary](#doc-comments)
- `long_help = <expr>`: `clap::Arg::long_help`
Expand Down
1 change: 1 addition & 0 deletions src/builder/mod.rs
Expand Up @@ -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;
Expand Down
217 changes: 129 additions & 88 deletions src/builder/value_parser.rs
Expand Up @@ -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<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()
}
}
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<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 i64 {
type Parser = RangedI64ValueParser<i64>;
fn value_parser() -> Self::Parser {
RangedI64ValueParser::new()
}
}

#[doc(hidden)]
#[derive(Debug)]
pub struct AutoValueParser<T>(std::marker::PhantomData<T>);
Expand All @@ -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<String> {
type Parser = ValueParser;
fn value_parser(&self) -> Self::Parser {
ValueParser::string()
}
}
impl ValueParserViaBuiltIn for &&AutoValueParser<std::ffi::OsString> {
type Parser = ValueParser;
fn value_parser(&self) -> Self::Parser {
ValueParser::os_string()
}
}
impl ValueParserViaBuiltIn for &&AutoValueParser<std::path::PathBuf> {
type Parser = ValueParser;
fn value_parser(&self) -> Self::Parser {
ValueParser::path_buf()
}
}
impl ValueParserViaBuiltIn for &&AutoValueParser<bool> {
type Parser = ValueParser;
fn value_parser(&self) -> Self::Parser {
ValueParser::bool()
}
}
impl ValueParserViaBuiltIn for &&AutoValueParser<u8> {
type Parser = RangedI64ValueParser<u8>;
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<i8> {
type Parser = RangedI64ValueParser<i8>;
impl<P: ValueParserFactory> ValueParserViaFactory for &&AutoValueParser<P> {
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<u16> {
type Parser = RangedI64ValueParser<u16>;
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<i16> {
type Parser = RangedI64ValueParser<i16>;
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<u32> {
type Parser = RangedI64ValueParser<u32>;
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<i32> {
type Parser = RangedI64ValueParser<i32>;
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<i64> {
type Parser = RangedI64ValueParser<i64>;
fn value_parser(&self) -> Self::Parser {
RangedI64ValueParser::new()
P::value_parser()
}
}

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -1784,18 +1835,8 @@ mod private {
pub trait ValueParserViaSelfSealed {}
impl<P: Into<ValueParser>> ValueParserViaSelfSealed for &&&AutoValueParser<P> {}

pub trait ValueParserViaBuiltInSealed {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<String> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<std::ffi::OsString> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<std::path::PathBuf> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<bool> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<u8> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<i8> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<u16> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<i16> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<u32> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<i32> {}
impl ValueParserViaBuiltInSealed for &&AutoValueParser<i64> {}
pub trait ValueParserViaFactorySealed {}
impl<P: ValueParserFactory> ValueParserViaFactorySealed for &&AutoValueParser<P> {}

pub trait ValueParserViaArgEnumSealed {}
impl<E: crate::ArgEnum> ValueParserViaArgEnumSealed for &AutoValueParser<E> {}
Expand Down

0 comments on commit 52c1841

Please sign in to comment.