Parse Vector of Vector arguments using Clap

Hi folks,

I figured out that using Clap I can parse a vector of enum (code below) and then run the program with --myarg first --myarg second --myarg first.

But is it possible to parse vector of vectors (Vec<Vec<MyEnum>> or Vec<Vec<String>>)? I'm not sure how exactly this would be specified as arguments but I'm OK with any style as long as I can get group of groups (vector of vectors).

Thank you.

#[derive(Clone, Debug, clap::ValueEnum)]
enum MyEnum {
    First,
    Second,
    Third,
}

#[derive(Clone, Debug, clap::Parser)]
#[command(name = "program", about = "program", rename_all = "snake_case")]
struct Xyz {
    #[arg(long, value_enum)]
    myarg: Vec<MyEnum>,
}

pub async fn runit() {
    let Xyz { myarg, .. } = <Xyz as clap::Parser>::parse();
    myarg.iter().enumerate().for_each(|(i, inp)| {
        println!("    {i}. {inp:?}");
    });
}

To prevent risking an XY situation, can you give an example of what exactly you're trying to do?

1 Like

Hello,

Just need to group multiple arguments into multiple groups - Vec<Vec<x> would be ideal.

To test it:

            myarg.iter().enumerate().for_each(|(i, x)| {
                x.iter().enumerate().for_each(|(i2, y)| {
                    println!("    {i}.{i2}. {y}");
                });
            });

If you care for using commas as the delimiter for the nested vectors, you can do this:

use clap::ValueEnum;

#[derive(Clone, Debug, ValueEnum)]
enum MyEnum {
    First,
    Second,
    Third,
}

#[derive(Clone, Debug, clap::Parser)]
#[command(name = "program", about = "program", rename_all = "snake_case")]
struct Xyz {
    #[arg(long, value_parser = parse_my_enum_vec)]
    myarg: Vec<Vec<MyEnum>>,
}

fn parse_my_enum_vec(s: &str) -> Result<Vec<MyEnum>, String> {
    let mut res = Vec::new();

    for x in s.split(',') {
        res.push(MyEnum::from_str(x, true)?);
    }

    Ok(res)
}

fn main() {
    let res = <Xyz as clap::Parser>::try_parse_from([
        "playground",
        "--myarg",
        "first,second,first",
        "--myarg",
        "third",
    ]);

    println!("{res:?}");
}

Playground.

3 Likes

That's fantastic! Thank you!

1 Like