When parsing integers from the CLI arguments with clap in a simple main.rs
the
standard way is to have a specific function for parsing hex values like that:
use clap::Parser;
#[derive(Parser, Debug)]
#[command(name = "parse-int-with-clap", version, author)]
struct Args {
/// left hand of addition
#[arg(short = 'a', value_parser = parse_hex_u8)]
a: u8,
/// right hand of addition
#[arg(short = 'b', value_parser = parse_hex_16)]
b: i16,
}
fn parse_hex_u8(s: &str) -> Result<u8, String> {
let s = s.trim_start_matches("0x");
u8::from_str_radix(s, 16).map_err(|e| e.to_string())
}
fn parse_hex_16(s: &str) -> Result<i16, String> {
let s = s.trim_start_matches("0x");
i16::from_str_radix(s, 16).map_err(|e| e.to_string())
}
fn main() {
let args = Args::parse();
println!("{:?}", args);
let Args { a, b } = args;
println!("{} + {} = {}", a, b, a as i16 + b);
println!("0x{:X} + 0x{:X} = 0x{:X}", a, b, a as i16 + b);
}
This works, but now we have a subtle bug when a user just inputs a decimal like
10
that will be translated to 0x10
, however the user did input 0xA
.
Getting flexible with parse_int
With parse_int we can simplify that by using a specific variant of the lot:
#[derive(Parser, Debug)]
#[command(name = "parse-int-with-clap", version, author)]
struct Args {
/// left hand of addition
#[arg(short = 'a', value_parser = parse_int::parse::<u8>)]
a: u8,
/// right hand of addition
#[arg(short = 'b', value_parser = parse_int::parse::<i16>)]
b: i16,
}
This saves us from writing out a function per data-type.
In addition now we correctly parse all the input 🎉