0

I have a number of arguments that when specified require that a specific argument is provided.

In the below example when b or c is specified it requires that a is specified.

Ideally this would be implemented like: Playground

use clap::Parser;

#[derive(Debug, Parser)]
struct Args {
    #[arg(long)]
    one: Option<String>,
    #[arg(long)]
    two: Option<InnerArgs>,
}
#[derive(Debug, Parser)]
struct InnerArgs {
    #[arg(long)]
    a: String,
    #[arg(long)]
    b: Option<String>,
    #[arg(long)]
    c: Option<String>,
}

fn main() {
    let args = Args::parse();
    println!("args: {args:?}");
}

Attempting this however produces errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `InnerArgs: Clone` is not satisfied
   --> src/main.rs:8:17
    |
8   |     two: Option<InnerArgs>,
    |                 ^^^^^^^^^ the trait `Clone` is not implemented for `InnerArgs`
    |
note: required by a bound in `ArgMatches::remove_one`
   --> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/clap-4.1.8/src/parser/matches/arg_matches.rs:389:32
    |
389 |     pub fn remove_one<T: Any + Clone + Send + Sync + 'static>(&mut self, id: &str) -> Option<T> {
    |                                ^^^^^ required by this bound in `ArgMatches::remove_one`
help: consider annotating `InnerArgs` with `#[derive(Clone)]`
    |
11  | #[derive(Clone)]
    |

error[E0599]: the method `value_parser` exists for reference `&&&&&&_AutoValueParser<InnerArgs>`, but its trait bounds were not satisfied
    --> src/main.rs:7:5
     |
7    |     #[arg(long)]
     |     ^ method cannot be called on `&&&&&&_AutoValueParser<InnerArgs>` due to unsatisfied trait bounds
...
11   | struct InnerArgs {
     | ----------------
     | |
     | doesn't satisfy `InnerArgs: Clone`
     | doesn't satisfy `InnerArgs: From<&'s std::ffi::OsStr>`
     | doesn't satisfy `InnerArgs: From<&'s str>`
     | doesn't satisfy `InnerArgs: From<OsString>`
     | doesn't satisfy `InnerArgs: From<std::string::String>`
     | doesn't satisfy `InnerArgs: FromStr`
     | doesn't satisfy `InnerArgs: ValueEnum`
     | doesn't satisfy `InnerArgs: ValueParserFactory`
     |
    ::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/clap-4.1.8/src/builder/value_parser.rs:2187:1
     |
2187 | pub struct _AutoValueParser<T>(std::marker::PhantomData<T>);
     | ------------------------------ doesn't satisfy `_: _ValueParserViaParse`
     |
     = note: the following trait bounds were not satisfied:
             `InnerArgs: ValueEnum`
             which is required by `&&&&&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaValueEnum`
             `InnerArgs: Clone`
             which is required by `&&&&&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaValueEnum`
             `InnerArgs: ValueParserFactory`
             which is required by `&&&&&&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaFactory`
             `InnerArgs: From<OsString>`
             which is required by `&&&&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaFromOsString`
             `InnerArgs: Clone`
             which is required by `&&&&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaFromOsString`
             `InnerArgs: From<&'s std::ffi::OsStr>`
             which is required by `&&&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaFromOsStr`
             `InnerArgs: Clone`
             which is required by `&&&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaFromOsStr`
             `InnerArgs: From<std::string::String>`
             which is required by `&&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaFromString`
             `InnerArgs: Clone`
             which is required by `&&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaFromString`
             `InnerArgs: From<&'s str>`
             which is required by `&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaFromStr`
             `InnerArgs: Clone`
             which is required by `&_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaFromStr`
             `InnerArgs: FromStr`
             which is required by `_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaParse`
             `InnerArgs: Clone`
             which is required by `_AutoValueParser<InnerArgs>: clap::builder::via_prelude::_ValueParserViaParse`
note: the traits `ValueEnum`, `ValueParserFactory`, `From`,  and `FromStr` must be implemented
    --> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/clap-4.1.8/src/builder/value_parser.rs:2090:1
     |
2090 | pub trait ValueParserFactory {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     |
    ::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/clap-4.1.8/src/derive.rs:374:1
     |
374  | pub trait ValueEnum: Sized + Clone {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    --> /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/convert/mod.rs:543:1
    --> /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/str/traits.rs:547:1
     = note: this error originates in the macro `clap::value_parser` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `InnerArgs` with `#[derive(Clone)]`
     |
11   | #[derive(Clone)]
     |

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `playground` due to 3 previous errors

I have seen Using a structure as a command line argument in clap it does not answer this question.

Jonathan Woollett-light
  • 2,813
  • 5
  • 30
  • 58

1 Answers1

1

If the intent is to require b and c when a is provided, you can do that with requires_all:

#[derive(Debug, Parser)]
struct Args {
    #[arg(long)]
    one: Option<String>,
    
    #[arg(long, requires_all=["b", "c"])]
    a: Option<String>,
    #[arg(long)]
    b: Option<String>,
    #[arg(long)]
    c: Option<String>,
}
cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • I believe the intent is for the dependency to go in the opposite direction, i.e. a `requires="a"` on both `b` and `c` – cafce25 Mar 20 '23 at 10:59