prefixopt 0.3.0

See Read Me. Automatically derive options from structs and enums to use with clap.
Documentation
extern crate clap;
extern crate prefixopt;

use prefixopt::*;
use parsable::*;
use concat_ref::*;

fn main() {
    let splitc = Split::with_prefix("o");
    let args = splitc.as_arguments();
    let app = args.bind_app(clap::App::new("testing"));
    let matches = app.get_matches();
    let split = splitc.override_arguments(Split::default(), &matches);
    println!("{:?}", split);
}


#[derive(Default, Debug)]
pub struct A {
    number: u64,
}
#[derive(Debug)]
pub enum Split {
    A(A),
    B(A, u64),
}

impl Default for Split {
    fn default() -> Split {
        Split::B(A { number: 5 }, 5)
    }
}
pub struct AC {
    number: Parsable<u64>,
}
pub struct SplitC {
    ag: String,
    a: AC,
    bg: String,
    b0: AC,
    b1: Parsable<u64>,
}
impl A {
    fn new(number: u64) -> A {
        A { number }
    }
}
impl PrefixOpt for A {
    type Container = AC;
}
impl PrefixOptContainer for AC {
    type Parsed = A;
    fn concat_prefix(prefix: &ConcatRef<&Display>) -> Self {
        Self { number: <u64 as PrefixOpt>::Container::concat_prefix(&prefix.append(&"number"))}
    }
    fn as_arguments(&self) -> Args {
        self.number.as_arguments()
    }
    fn override_arguments(&self, def: Self::Parsed, matches: &clap::ArgMatches) -> Option<Self::Parsed> {
        self.number.override_arguments(def.number, matches).map(A::new)
    }
}
impl PrefixOpt for Split {
    type Container = SplitC;
}
impl PrefixOptContainer for SplitC {
    type Parsed = Split;
    fn concat_prefix(prefix: &ConcatRef<&Display>) -> Self {
        SplitC {
            ag: prefix.append(&"A").into(),
            a: <A as PrefixOpt>::Container::concat_prefix(&prefix.append(&"A.0")),
            bg: prefix.append(&"B").into(),
            b0: A::with_prefix(&prefix.append(&"B.0")),
            b1: u64::with_prefix(&prefix.append(&"B.1")),
        }
    }
    fn as_arguments(&self) -> Args {
        let ag = clap::ArgGroup::with_name(&self.ag).multiple(true);
        let bg = clap::ArgGroup::with_name(&self.bg).multiple(true).conflicts_with(&self.ag);
        let all_groups = clap::ArgGroup::with_name("All").arg(&self.ag).arg(&self.bg);
        let a = self.a.as_arguments();
        let b0 = self.b0.as_arguments();
        let b1 = self.b1.as_arguments();
        let mut o = Args::default().add_group(ag).add_group(bg).add_group(all_groups);
        o.extend(a.map_arg(|arg| arg.group(&self.ag)));
        o.extend(b0.map_arg(|arg| arg.group(&self.bg)));
        o.extend(b1.map_arg(|arg| arg.group(&self.bg)));
        return o;
    }
    fn override_arguments(&self, def: Self::Parsed, matches: &clap::ArgMatches) -> Option<Self::Parsed> {
        macro_rules! try_opt {
            ($expression:expr) => (
                if let Some(p) = $expression {p} else {return None;}
            )
        }
        match (def, matches.is_present(&self.ag), matches.is_present(&self.bg)) {
            (Split::A(a), true, _) => self.a.override_arguments(a, matches).map(Split::A),
            (_, true, _) => self.a.override_arguments(A::default(), matches).map(Split::A),
            (Split::B(b0, b1), false, true) => {
                let b0 = try_opt!(self.b0.override_arguments(b0, matches));
                let b1 = try_opt!(self.b1.override_arguments(b1, matches));
                Some(Split::B(b0, b1))
            },
            (_, false, true) => {
                let b0 = try_opt!(self.b0.override_arguments(A::default(), matches));
                let b1 = try_opt!(self.b1.override_arguments(u64::default(), matches));
                Some(Split::B(b0, b1))
            },
            (_,_,_) => Some(Self::Parsed::default()),
        }
    }
}