Hi, I recently started moving one of my binaries to clap. Unfortunately, I don't seem to understand how Clap's derive feature work. I've seen their example, but I'm not sure how to combine those.
My main issue is that no matter which approach I try, I always end up with an issue stating that I must manually implement std::str::FromStr for my inner Structs/enums.
What I want to achieve is something like: ./binary -foo RepoEnum -bar RepoEnum
People might skip passing either foo or bar (It's also acceptable if the binary allows skipping both).
The Argument passed with foo or bar is an enum similar to:
enum RepoEnum {
Stable,
Head,
Local(PathBuf), // Local(String) would also be ok.
}
I have tried a lot of approaches. For example I've split the enum into a Local<Stable/Head> enum and a Struct { local: PathBuf } and used grouping to accept exactly one of the two for both foo and bar. However, as long as I have the Local(PathBuf) Variant showing up somewhere it asks me to implement FromStr, which makes me believe that I'm using it incorrectly. Which layout would be better, can someone please give me a hint?
Thank you, but that is too straight-forward, it gives me the usual error. I just haven't included the source-code in my original post, because I tried like 5 different variations of it and my post would become unreadable.
This approach only seems to work with simple enums which do not include inner values like a PathBuf. Do you know how I can work around that?
I do need the ability for people to specify a local path to a repository.
Here is the error for the example you suggested:
#[derive(Parser)]
pub struct Input {
/// some regular input
#[clap(long = "bar", arg_enum)]
bar: Repo,
/// some special input argument
#[clap(long = "foo", arg_enum)]
foo: Option<Repo>,
}
/// Used to decide which Version should be used
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ArgEnum)]
pub enum Repo {
/// Use the latest stable release
Stable,
/// Use the current head from Github
Head,
/// Use a local repository at the given path
Local(String),
//Local(PathBuf),
}
This gives errors in the style of:
error[E0277]: the trait bound `utils::Repo: ArgEnum` is not satisfied
--> src/code/utils.rs:26:11
|
26 | foo: Repo,
| ^^^^ the trait `ArgEnum` is not implemented for `utils::Repo`
|
note: required by `clap::ArgEnum::from_str`
--> /home/zusez4/.cargo/registry/src/github.com-1ecc6299db9ec823/clap-3.1.5/src/derive.rs:425:5
|
425 | fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Is the intent that "stable" is converted to RepoEnum::Stable, "head" to RepoEnum::Head and everything else like "something" to RepoEnum::Local("something")? Or do you want the argument to look something like "local=something", or something else?
According to clap's derive tutorial, ArgEnum is meant for situations where you have specific values you want to test for:
If you have arguments of specific values you want to test for, you can derive ArgEnum .
This allows you specify the valid values for that argument. If the user does not use one of those specific values, they will receive a graceful exit with error message informing them of the mistake, and what the possible valid values are
Indeed, my mistake was the expectation that Enum Variants with inner values would be supported by automatically taking the following command-line value as candidate for the inner value.
Then I also had been using ArgGroups wrong in the first attempt, however I now was able to fix both without implementing FromStr manually.Thanks to you and all the friendly people from discord https://github.com/EnzymeAD/Enzyme/pull/519#issuecomment-1062552345