5

I want to use the clap derive API in order to parse an Ipv4Addr.

#![allow(unused)]
use clap; // 3.1.6
use clap::Parser;
use std::net::Ipv4Addr;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
    
    #[clap(short, long, parse(from_str))]
    ip_dst: Ipv4Addr,

}

fn main() {
    let args = Args::parse();
}

My attempt gives the following error even though Ipv4Addr seems to implement FromStr which provides from_str

error[E0277]: the trait bound `Ipv4Addr: From<&str>` is not satisfied
  --> src/main.rs:10:31
   |
10 |     #[clap(short, long, parse(from_str))]
   |                               ^^^^^^^^ the trait `From<&str>` is not implemented for `Ipv4Addr`
   |
   = help: the following implementations were found:
             <Ipv4Addr as From<[u8; 4]>>
             <Ipv4Addr as From<u32>>

For more information about this error, try `rustc --explain E0277`.

My Questions are:

  • Why isn't the method provided by FromStr used?
  • How can I fix the program to do what I want?
jonathan-dev
  • 330
  • 1
  • 3
  • 16

3 Answers3

6

What you want is what is used by default (since Ipv4Addr implements FromStr), without specifiying any parse option:

use clap; // 3.1.6
use clap::Parser;
use std::net::Ipv4Addr;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
    #[clap(short, long)]
    ip_dst: Ipv4Addr,
}

Playground

Otherwise, you need to use try_from_str as per the example:

#![allow(unused)]
use clap; // 3.1.6
use clap::Parser;
use std::net::Ipv4Addr;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
    
    #[clap(short, long, parse(try_from_str))]
    ip_dst: Ipv4Addr,

}

Playground

Netwave
  • 40,134
  • 6
  • 50
  • 93
  • 1
    the second playground has an issue (which I also have locally). I suspect it is because not version of clap is 4.0 and not 3.1. The errors are that the `method parse found for struct must have a self parameter`. The second error is about the `try_from_str` that is not in this scope. – Patrick Desjardins Jan 13 '23 at 01:19
  • Instead, it seems that one solution is to use `value_parser`. Some information is available here https://docs.rs/clap/latest/clap/_cookbook/typed_derive/index.html – Patrick Desjardins Jan 13 '23 at 01:34
3

Ipv4Addr implements FromStr but not From<&str> which is the From trait with &str as a parameter. If you want to use FromStr, specify parse(try_from_str) or omit it since it's the default.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
2

Update for Clap v4

use clap::{arg, value_parser, Command}; // Clap v4
use std::net::Ipv4Addr;

fn main() {
    let matches = Command::new("clap-test")
        .arg(
            arg!(--ip <VALUE>)
                .default_value("127.0.0.1")
                .value_parser(value_parser!(Ipv4Addr)),
        )
        .get_matches();

    println!(
        "IP {:?}",
        matches.get_one::<Ipv4Addr>("ip").expect("required"),
    );
}
Daniel
  • 3,243
  • 2
  • 32
  • 31