Add validator support
RazrFalcon opened this issue · comments
Like:
fn my_func(value: &str) -> Option<u32> {} // or Result
#[options(help = "Sets the target DPI", meta = "DPI", default = "96", validate=my_func)]
dpi: Option<u32>,
The code generated by gumdrop
uses the standard FromStr
trait to generate field values. You can implement this on a custom type to get the functionality you want (in conjunction with a manual Default
implementation as outlined in #12):
#[derive(Default, Options)]
struct Options {
dpi: Dpi,
// ...
}
struct Dpi(u32);
impl FromStr for Dpi {
// This could be a custom error type, but I'm being terse here.
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let n = s.parse().map_err(|_| "invalid number")?;
if is_valid_dpi(n) {
Ok(Dpi(n))
} else {
Err("invalid dpi value")
}
}
}
Hm... It's an interesting idea, but I think that it's missed from docs.
The main gumdrop
documentation does mention FromStr
, but only once, in passing. So, that's fair.
An example with a custom FromStr
implementation could be used to highlight this capability.
I still think that a function pointer will lead to a smaller and cleaner code, but it's fine for now.
You can close it.
The meaning of a named function in an option attribute is not obvious, though. If you're visually scanning over the code and you see it, what do you expect the signature of the function to be? fn(T) -> Result<T, Error>
? fn(&T) -> Result<(), Error>
? fn(&str) -> Result<T, Error>
? None of these are intuitively the obvious choice. However, FromStr
is a standard trait and makes argument value parsing an intuitively obvious one-step process.
And again, structopt
doesn't think that this a problem.
https://docs.rs/structopt/0.2.10/structopt/#custom-string-parsers
Allowing different types of parsing functions seems like a reasonable solution. I'll see what I can do.
I've added an implementation for custom parsers using the parse(...)
attribute, similar to structopt
. Let me know if it works as expected.
Excellent! But it still requires FromStr
for a type. I'm using:
parse(try_from_str = "parse_indent")
// and
fn parse_indent(s: &str) -> Result<svgdom::Indent, &'static str> {}
The test code shows an example of parsing types that do not implement FromStr
: https://github.com/murarth/gumdrop/blob/master/tests/options.rs#L853-L891
You mean fn parse_bar(s: &str) -> Result<Bar, <u32 as FromStr>::Err> { s.parse().map(Bar) }
? That's what I'm using.
Do'h! That was my mistake. I've set parse
only for one type, not both.
Thanks a lot! It works as expected.