Structopt: Parse args from HashMap

Created on 21 Apr 2018  路  6Comments  路  Source: TeXitoi/structopt

Is this possible under the current implementation?

I have a HashMap<&str, &str> which are key:value (arg name/arg value)

question

Most helpful comment

You don't need macro:

#[macro_use]
extern crate structopt;

use std::collections::HashMap;

#[derive(StructOpt, Debug)]
struct MyParams {
    // you need parse for this field to be an option and not a flag
    #[structopt(long = "debug", parse(try_from_str))]
    debug: bool,

    #[structopt(long = "speed")]
    speed: f64,

    #[structopt(long = "name")]
    name: String,
}

// Maybe overly generic
fn structopt_from_map<T, I, K, V>(args: I) -> Result<T, structopt::clap::Error>
where
    T: structopt::StructOpt,
    I: IntoIterator<Item=(K, V)>,
    K: std::fmt::Display,
    V: std::fmt::Display,
{
    let mut v = vec!["exec-name".to_string()];
    v.extend(args.into_iter().map(|(k, v)| format!("--{}={}", k, v)));
    T::from_iter_safe(&v)
}

fn main() {
    let mut args = HashMap::new();
    args.insert("debug", "true");
    args.insert("speed", "24.55");
    args.insert("name", "sharksforarms");

    let opt: Result<MyParams, _> = structopt_from_map(&args);
    println!("{:?}", opt);
}

All 6 comments

Sorry, I don't understand your needs. Can you five a rough example of what you would like to do?

Something like the following:

#[macro_use]
extern crate structopt;

use std::path::PathBuf;
use structopt::StructOpt;

/// A basic example
#[derive(StructOpt, Debug)]
#[structopt(name = "basic")]
struct Opt {
    /// Activate debug mode
    #[structopt(short = "d", long = "debug")]
    debug: bool,

    /// Set speed
    #[structopt(short = "s", long = "speed", default_value = "42")]
    speed: f64,
}

fn main() {
    let mut args = HashMap::new();
    args.insert("debug", "true");
    args.insert("speed", "24.55");

    let opt = Opt::from_hashmap(&args);
    println!("{:?}", opt);
}

Here's my original attempt (using serde) which fails:
https://play.rust-lang.org/?gist=541f423f06396570934b8bbaca05f549&version=stable

Ha, OK. This kind of features is more toward clap. You can also look at #72.

A dirty workaround would be something like that:

let mut v = vec["exec-name".to_string()];
v.extend(args.iter().map|(k, v)| format!("--{}={}", k, v);
let opt = Opt::from_iter(&v);

(not tested, for the idea)

Tested version:

#[macro_use]
extern crate structopt;

use std::collections::HashMap;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
struct Opt {
    // you need parse for this field to be an option and not a flag
    #[structopt(long = "debug", parse(try_from_str))]
    debug: bool,
    #[structopt(long = "speed")]
    speed: f64,
}

fn main() {
    let mut args = HashMap::new();
    args.insert("debug", "true");
    args.insert("speed", "24.55");

    let mut v = vec!["exec-name".to_string()];
    v.extend(args.iter().map(|(k, v)| format!("--{}={}", k, v)));
    let opt = Opt::from_iter(&v);
    println!("{:?}", opt);
}

Thanks!! Enhanced the example a bit using the new from_iter_safe (thanks @quodlibetor !!)

#[macro_use]
extern crate structopt;

use std::collections::HashMap;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
struct MyParams {
    // you need parse for this field to be an option and not a flag
    #[structopt(long = "debug", parse(try_from_str))]
    debug: bool,

    #[structopt(long = "speed")]
    speed: f64,

    #[structopt(long = "name")]
    name: String,
}

macro_rules! structopt_from_map {
    ($map:expr, $type:ident) => {{
        let mut v = vec!["exec-name".to_string()];
        v.extend($map.iter().map(|(k, v)| format!("--{}={}", k, v)));
        $type::from_iter_safe(&v)
    }};
}

fn main() {
    let mut args = HashMap::new();
    args.insert("debug", "true");
    args.insert("speed", "24.55");
    args.insert("name", "sharksforarms");

    let opt = structopt_from_map!(&args, MyParams);
    println!("{:?}", opt);
}

You don't need macro:

#[macro_use]
extern crate structopt;

use std::collections::HashMap;

#[derive(StructOpt, Debug)]
struct MyParams {
    // you need parse for this field to be an option and not a flag
    #[structopt(long = "debug", parse(try_from_str))]
    debug: bool,

    #[structopt(long = "speed")]
    speed: f64,

    #[structopt(long = "name")]
    name: String,
}

// Maybe overly generic
fn structopt_from_map<T, I, K, V>(args: I) -> Result<T, structopt::clap::Error>
where
    T: structopt::StructOpt,
    I: IntoIterator<Item=(K, V)>,
    K: std::fmt::Display,
    V: std::fmt::Display,
{
    let mut v = vec!["exec-name".to_string()];
    v.extend(args.into_iter().map(|(k, v)| format!("--{}={}", k, v)));
    T::from_iter_safe(&v)
}

fn main() {
    let mut args = HashMap::new();
    args.insert("debug", "true");
    args.insert("speed", "24.55");
    args.insert("name", "sharksforarms");

    let opt: Result<MyParams, _> = structopt_from_map(&args);
    println!("{:?}", opt);
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

epage picture epage  路  7Comments

tathanhdinh picture tathanhdinh  路  6Comments

tathanhdinh picture tathanhdinh  路  3Comments

coder543 picture coder543  路  9Comments

sphynx picture sphynx  路  9Comments