I have this code:
#[derive(StructOpt)]
pub struct Opt {
/// Data stream to send to the device
#[structopt(help = "Data to send", parse(try_from_str = "parse_hex"))]
data: Vec<u8>,
}
fn parse_hex(s: &str) -> Result<u8, ParseIntError> {
u8::from_str_radix(s, 16)
}
This works for myexe AA BB
, but I need to take myexe AABB
as input.
Is there a way to pass a custom parser to structopt
to parse AABB
into a Vec<u8>
? I need to parse only the second form (no space).
I know I can do it in 2 steps (storing into a String
in the struct then parse it, but I like the idea that my Opt
has the final type for everything.
I tried a parser like this:
fn parse_hex_string(s: &str) -> Result<Vec<u8>, ParseIntError>
The StructOpt
macro panics about type mismatches because it seems to produce a Vec<Vec<u8>>
.
StructOpt makes the distinction that a Vec<T>
will always map to multiple arguments:
Vec<T: FromStr>
list of options or the other positional arguments
.takes_value(true).multiple(true)
That means you need a single type to represent your data. Replace your Vec<u8>
with a newtype:
#[derive(Debug)]
struct HexData(Vec<u8>);
#[derive(Debug, StructOpt)]
pub struct Opt {
/// Data stream to send to the device
#[structopt(help = "Data to send")]
data: HexData,
}
This leads to the error:
error[E0277]: the trait bound `HexData: std::str::FromStr` is not satisfied
--> src/main.rs:16:10
|
16 | #[derive(StructOpt)]
| ^^^^^^^^^ the trait `std::str::FromStr` is not implemented for `HexData`
|
= note: required by `std::str::FromStr::from_str`
Let's implement FromStr
:
impl FromStr for HexData {
type Err = hex::FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
hex::decode(s).map(HexData)
}
}
And it works:
$ cargo run -- DEADBEEF
HexData([222, 173, 190, 239])
$ cargo run -- ZZZZ
error: Invalid value for '<data>': Invalid character 'Z' at position 0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With