logo
Available on crate feature unstable-doc only.
Expand description

Example: Custom Types (Derive API)

use clap::Parser;
use std::error::Error;

#[derive(Parser, Debug)] // requires `derive` feature
struct Args {
    /// Implicitly using `std::str::FromStr`
    #[clap(short = 'O', value_parser)]
    optimization: Option<usize>,

    /// Allow invalid UTF-8 paths
    #[clap(short = 'I', value_parser, value_name = "DIR", value_hint = clap::ValueHint::DirPath)]
    include: Option<std::path::PathBuf>,

    /// Handle IP addresses
    #[clap(long, value_parser)]
    bind: Option<std::net::IpAddr>,

    /// Allow human-readable durations
    #[clap(long, value_parser)]
    sleep: Option<humantime::Duration>,

    /// Hand-written parser for tuples
    #[clap(short = 'D', value_parser = parse_key_val::<String, i32>)]
    defines: Vec<(String, i32)>,
}

/// Parse a single key-value pair
fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
where
    T: std::str::FromStr,
    T::Err: Error + Send + Sync + 'static,
    U: std::str::FromStr,
    U::Err: Error + Send + Sync + 'static,
{
    let pos = s
        .find('=')
        .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
    Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
}

fn main() {
    let args = Args::parse();
    println!("{:?}", args);
}

This requires enabling the derive feature flag.

Help:

$ typed-derive --help
clap 

USAGE:
    typed-derive[EXE] [OPTIONS]

OPTIONS:
        --bind <BIND>        Handle IP addresses
    -D <DEFINES>             Hand-written parser for tuples
    -h, --help               Print help information
    -I <DIR>                 Allow invalid UTF-8 paths
    -O <OPTIMIZATION>        Implicitly using `std::str::FromStr`
        --sleep <SLEEP>      Allow human-readable durations

Optimization-level (number)

$ typed-derive -O 1
Args { optimization: Some(1), include: None, bind: None, sleep: None, defines: [] }

$ typed-derive -O plaid
? failed
error: Invalid value "plaid" for '-O <OPTIMIZATION>': invalid digit found in string

For more information try --help

Include (path)

$ typed-derive -I../hello
Args { optimization: None, include: Some("../hello"), bind: None, sleep: None, defines: [] }

IP Address

$ typed-derive --bind 192.0.0.1
Args { optimization: None, include: None, bind: Some(192.0.0.1), sleep: None, defines: [] }

$ typed-derive --bind localhost
? failed
error: Invalid value "localhost" for '--bind <BIND>': invalid IP address syntax

For more information try --help

Time

$ typed-derive --sleep 10s
Args { optimization: None, include: None, bind: None, sleep: Some(Duration(10s)), defines: [] }

$ typed-derive --sleep forever
? failed
error: Invalid value "forever" for '--sleep <SLEEP>': expected number at 0

For more information try --help

Defines (key-value pairs)

$ typed-derive -D Foo=10 -D Alice=30
Args { optimization: None, include: None, bind: None, sleep: None, defines: [("Foo", 10), ("Alice", 30)] }

$ typed-derive -D Foo
? failed
error: Invalid value "Foo" for '-D <DEFINES>': invalid KEY=value: no `=` found in `Foo`

For more information try --help

$ typed-derive -D Foo=Bar
? failed
error: Invalid value "Foo=Bar" for '-D <DEFINES>': invalid digit found in string

For more information try --help