Skip to content

Commit

Permalink
feat(arg): allow lifetimes other than 'static in arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
kbknapp committed Apr 1, 2015
1 parent 76f015e commit 9e8c1fb
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 96 deletions.
64 changes: 32 additions & 32 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use args::{PosArg, PosBuilder};
///
/// // Your pogram logic starts here...
/// ```
pub struct App<'a, 'v, 'ab, 'u> {
pub struct App<'a, 'v, 'ab, 'u, 'ar> {
// The name displayed to the user when showing version and help/usage information
name: String,
// A string of author(s) if desired. Displayed when showing help/usage information
Expand All @@ -45,26 +45,26 @@ pub struct App<'a, 'v, 'ab, 'u> {
version: Option<&'v str>,
// A brief explaination of the program that gets displayed to the user when shown help/usage information
about: Option<&'ab str>,
flags: HashMap<&'static str, FlagBuilder>,
opts: HashMap<&'static str, OptBuilder>,
positionals_idx: BTreeMap<u8, PosBuilder>,
subcommands: HashMap<String, App<'a, 'v, 'ab, 'u>>,
flags: HashMap<&'ar str, FlagBuilder<'ar>>,
opts: HashMap<&'ar str, OptBuilder<'ar>>,
positionals_idx: BTreeMap<u8, PosBuilder<'ar>>,
subcommands: HashMap<String, App<'a, 'v, 'ab, 'u, 'ar>>,
needs_long_help: bool,
needs_long_version: bool,
needs_short_help: bool,
needs_short_version: bool,
needs_subcmd_help: bool,
required: HashSet<&'static str>,
arg_list: HashSet<&'static str>,
required: HashSet<&'ar str>,
arg_list: HashSet<&'ar str>,
short_list: HashSet<char>,
long_list: HashSet<&'static str>,
blacklist: HashSet<&'static str>,
long_list: HashSet<&'ar str>,
blacklist: HashSet<&'ar str>,
usage_str: Option<&'u str>,
bin_name: Option<String>

}

impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
/// Creates a new instance of an application requiring a name (such as the binary). Will be displayed
/// to the user when they print version or help and usage information.
///
Expand All @@ -75,7 +75,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
/// let prog = App::new("myprog")
/// # .get_matches();
/// ```
pub fn new<'n>(n: &'n str) -> App<'a, 'v, 'ab, 'u> {
pub fn new<'n>(n: &'n str) -> App<'a, 'v, 'ab, 'u, 'ar> {
App {
name: n.to_owned(),
author: None,
Expand Down Expand Up @@ -110,7 +110,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
/// .author("Kevin <[email protected]>")
/// # .get_matches();
/// ```
pub fn author(mut self, a: &'a str) -> App<'a, 'v, 'ab, 'u> {
pub fn author(mut self, a: &'a str) -> App<'a, 'v, 'ab, 'u, 'ar> {
self.author = Some(a);
self
}
Expand All @@ -125,7 +125,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
/// .about("Does really amazing things to great people")
/// # .get_matches();
/// ```
pub fn about(mut self, a: &'ab str) -> App<'a, 'v, 'ab, 'u > {
pub fn about(mut self, a: &'ab str) -> App<'a, 'v, 'ab, 'u, 'ar> {
self.about = Some(a);
self
}
Expand All @@ -140,7 +140,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
/// .version("v0.1.24")
/// # .get_matches();
/// ```
pub fn version(mut self, v: &'v str) -> App<'a, 'v, 'ab, 'u> {
pub fn version(mut self, v: &'v str) -> App<'a, 'v, 'ab, 'u, 'ar> {
self.version = Some(v);
self
}
Expand All @@ -162,7 +162,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
/// .usage("myapp [-clDas] <some_file>")
/// # .get_matches();
/// ```
pub fn usage(mut self, u: &'u str) -> App<'a, 'v, 'ab, 'u> {
pub fn usage(mut self, u: &'u str) -> App<'a, 'v, 'ab, 'u, 'ar> {
self.usage_str = Some(u);
self
}
Expand All @@ -180,7 +180,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
/// )
/// # .get_matches();
/// ```
pub fn arg(mut self, a: Arg) -> App<'a, 'v, 'ab, 'u> {
pub fn arg<'l, 'h, 'b, 'r>(mut self, a: Arg<'ar, 'ar, 'ar, 'ar, 'ar>) -> App<'a, 'v, 'ab, 'u, 'ar> {
if self.arg_list.contains(a.name) {
panic!("Argument name must be unique, \"{}\" is already in use", a.name);
} else {
Expand Down Expand Up @@ -289,7 +289,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
/// Arg::new("debug").short("d")])
/// # .get_matches();
/// ```
pub fn args(mut self, args: Vec<Arg>) -> App<'a, 'v, 'ab, 'u> {
pub fn args(mut self, args: Vec<Arg<'ar, 'ar, 'ar, 'ar, 'ar>>) -> App<'a, 'v, 'ab, 'u, 'ar> {
for arg in args.into_iter() {
self = self.arg(arg);
}
Expand All @@ -314,7 +314,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
/// // Additional subcommand configuration goes here, such as arguments...
/// # .get_matches();
/// ```
pub fn subcommand(mut self, subcmd: App<'a, 'v, 'ab, 'u>) -> App<'a, 'v, 'ab, 'u> {
pub fn subcommand(mut self, subcmd: App<'a, 'v, 'ab, 'u, 'ar>) -> App<'a, 'v, 'ab, 'u, 'ar> {
if subcmd.name == "help" { self.needs_subcmd_help = false; }
self.subcommands.insert(subcmd.name.clone(), subcmd);
self
Expand All @@ -333,7 +333,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
/// SubCommand::new("debug").about("Controls debug functionality")])
/// # .get_matches();
/// ```
pub fn subcommands(mut self, subcmds: Vec<App<'a, 'v, 'ab, 'u>>) -> App<'a, 'v, 'ab, 'u> {
pub fn subcommands(mut self, subcmds: Vec<App<'a, 'v, 'ab, 'u, 'ar>>) -> App<'a, 'v, 'ab, 'u, 'ar> {
for subcmd in subcmds.into_iter() {
self = self.subcommand(subcmd);
}
Expand Down Expand Up @@ -449,7 +449,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
if quit { env::set_exit_status(1); self.exit(); }
}

pub fn get_matches(mut self) -> ArgMatches {
pub fn get_matches(mut self) -> ArgMatches<'ar> {
let mut matches = ArgMatches::new();

let args = env::args().collect::<Vec<_>>();
Expand All @@ -468,12 +468,12 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
matches
}

fn get_matches_from(&mut self, matches: &mut ArgMatches, it: &mut IntoIter<String>) {
fn get_matches_from(&mut self, matches: &mut ArgMatches<'ar>, it: &mut IntoIter<String>) {
self.create_help_and_version();

let mut pos_only = false;
let mut subcmd_name: Option<String> = None;
let mut needs_val_of: Option<&'static str> = None;
let mut needs_val_of: Option<&str> = None;
let mut pos_counter = 1;
while let Some(arg) = it.next() {
let arg_slice = &arg[..];
Expand Down Expand Up @@ -518,14 +518,14 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
format!("Found positional argument {}, but {} doesn't accept any", arg, self.name),
true, true);
}
if let Some(ref p) = self.positionals_idx.get(&pos_counter) {
if let Some(p) = self.positionals_idx.get(&pos_counter) {
if self.blacklist.contains(p.name) {
self.report_error(format!("The argument \"{}\" is mutually exclusive with one or more other arguments", arg),
true, true);
}

matches.positionals.insert(p.name, PosArg{
name: p.name,
name: p.name.to_owned(),
value: arg.clone(),
});

Expand Down Expand Up @@ -616,7 +616,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
}
}

fn parse_long_arg(&mut self, matches: &mut ArgMatches ,full_arg: &String) -> Option<&'static str> {
fn parse_long_arg(&mut self, matches: &mut ArgMatches<'ar> ,full_arg: &String) -> Option<&'ar str> {
let mut arg = full_arg.trim_left_matches(|c| c == '-');

if arg == "help" && self.needs_long_help {
Expand Down Expand Up @@ -656,7 +656,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
}
} else {
matches.opts.insert(v.name, OptArg{
name: v.name,
name: v.name.to_owned(),
occurrences: 1,
values: if arg_val.is_some() { vec![arg_val.clone().unwrap()]} else {vec![]}
});
Expand Down Expand Up @@ -706,7 +706,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
}
if !done {
matches.flags.insert(v.name, FlagArg{
name: v.name,
name: v.name.to_owned(),
occurrences: 1
});
}
Expand Down Expand Up @@ -742,7 +742,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
unreachable!();
}

fn parse_short_arg(&mut self, matches: &mut ArgMatches ,full_arg: &String) -> Option<&'static str> {
fn parse_short_arg(&mut self, matches: &mut ArgMatches<'ar> ,full_arg: &String) -> Option<&'ar str> {
let arg = &full_arg[..].trim_left_matches(|c| c == '-');
if arg.len() > 1 {
// Multiple flags using short i.e. -bgHlS
Expand Down Expand Up @@ -778,7 +778,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
}
} else {
matches.opts.insert(v.name, OptArg{
name: v.name,
name: v.name.to_owned(),
occurrences: 1,
values: vec![]
});
Expand Down Expand Up @@ -811,7 +811,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
unreachable!();
}

fn parse_single_short_flag(&mut self, matches: &mut ArgMatches, arg: char) -> bool {
fn parse_single_short_flag(&mut self, matches: &mut ArgMatches<'ar>, arg: char) -> bool {
for v in self.flags.values().filter(|&v| v.short.is_some()).filter(|&v| v.short.unwrap() == arg) {
// Ensure this flag isn't on the mutually excludes list
if self.blacklist.contains(v.name) {
Expand All @@ -831,7 +831,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
}
if !done {
matches.flags.insert(v.name, FlagArg{
name: v.name,
name: v.name.to_owned(),
occurrences: 1
});
}
Expand Down Expand Up @@ -864,7 +864,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
false
}

fn validate_blacklist(&self, matches: &ArgMatches) {
fn validate_blacklist(&self, matches: &ArgMatches<'ar>) {
for name in self.blacklist.iter() {
if matches.flags.contains_key(name) {
self.report_error(format!("The argument {} is mutually exclusive with one or more other arguments",
Expand Down
38 changes: 19 additions & 19 deletions src/args/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@
/// .takes_value(true)
/// .help("Provides a config file to myprog")
/// # ).get_matches();
pub struct Arg {
pub struct Arg<'n, 'l, 'h, 'b, 'r> {
/// The unique name of the argument, required
pub name: &'static str,
pub name: &'n str,
/// The short version (i.e. single character) of the argument, no preceding `-`
/// **NOTE:** `short` is mutually exclusive with `index`
pub short: Option<char>,
/// The long version of the flag (i.e. word) without the preceding `--`
/// **NOTE:** `long` is mutually exclusive with `index`
pub long: Option<&'static str>,
pub long: Option<&'l str>,
/// The string of text that will displayed to the user when the application's
/// `help` text is displayed
pub help: Option<&'static str>,
pub help: Option<&'h str>,
/// If this is a required by default when using the command line program
/// i.e. a configuration file that's required for the program to function
/// **NOTE:** required by default means, it is required *until* mutually
Expand All @@ -46,13 +46,13 @@ pub struct Arg {
/// I.e. `-v -v -v` or `-vvv`
pub multiple: bool,
/// A list of names for other arguments that *may not* be used with this flag
pub blacklist: Option<Vec<&'static str>>,
pub blacklist: Option<Vec<&'b str>>,
/// A list of names of other arguments that are *required* to be used when
/// this flag is used
pub requires: Option<Vec<&'static str>>
pub requires: Option<Vec<&'r str>>
}

impl Arg {
impl<'n, 'l, 'h, 'b, 'r> Arg<'n, 'l, 'h, 'b, 'r> {
/// Creates a new instace of `Arg` using a unique string name.
/// The name will be used by the library consumer to get information about
/// whether or not the argument was used at runtime.
Expand All @@ -70,7 +70,7 @@ impl Arg {
/// Arg::new("conifg")
/// # .short("c")
/// # ).get_matches();
pub fn new(n: &'static str) -> Arg {
pub fn new(n: &'n str) -> Arg<'n, 'l, 'h, 'b, 'r> {
Arg {
name: n,
short: None,
Expand Down Expand Up @@ -104,7 +104,7 @@ impl Arg {
/// # Arg::new("conifg")
/// .short("c")
/// # ).get_matches();
pub fn short(mut self, s: &'static str) -> Arg {
pub fn short(mut self, s: &str) -> Arg<'n, 'l, 'h, 'b, 'r> {
self.short = s.trim_left_matches(|c| c == '-').chars().nth(0);
self
}
Expand All @@ -128,7 +128,7 @@ impl Arg {
/// # Arg::new("conifg")
/// .long("config")
/// # ).get_matches();
pub fn long(mut self, l: &'static str) -> Arg {
pub fn long(mut self, l: &'l str) -> Arg<'n, 'l, 'h, 'b, 'r> {
self.long = Some(l.trim_left_matches(|c| c == '-'));
self
}
Expand All @@ -145,7 +145,7 @@ impl Arg {
/// # Arg::new("conifg")
/// .help("The config file used by the myprog")
/// # ).get_matches();
pub fn help(mut self, h: &'static str) -> Arg {
pub fn help(mut self, h: &'h str) -> Arg<'n, 'l, 'h, 'b, 'r> {
self.help = Some(h);
self
}
Expand All @@ -168,7 +168,7 @@ impl Arg {
/// # Arg::new("conifg")
/// .required(true)
/// # ).get_matches();
pub fn required(mut self, r: bool) -> Arg {
pub fn required(mut self, r: bool) -> Arg<'n, 'l, 'h, 'b, 'r> {
self.required = r;
self
}
Expand All @@ -187,7 +187,7 @@ impl Arg {
/// # let myprog = App::new("myprog").arg(Arg::new("conifg")
/// .mutually_excludes("debug")
/// # ).get_matches();
pub fn mutually_excludes(mut self, name: &'static str) -> Arg {
pub fn mutually_excludes(mut self, name: &'b str) -> Arg<'n, 'l, 'h, 'b, 'r> {
if let Some(ref mut vec) = self.blacklist {
vec.push(name);
} else {
Expand All @@ -211,7 +211,7 @@ impl Arg {
/// .mutually_excludes_all(
/// vec!["debug", "input"])
/// # ).get_matches();
pub fn mutually_excludes_all(mut self, names: Vec<&'static str>) -> Arg {
pub fn mutually_excludes_all(mut self, names: Vec<&'b str>) -> Arg<'n, 'l, 'h, 'b, 'r> {
if let Some(ref mut vec) = self.blacklist {
for n in names {
vec.push(n);
Expand All @@ -234,7 +234,7 @@ impl Arg {
/// # let myprog = App::new("myprog").arg(Arg::new("conifg")
/// .requires("debug")
/// # ).get_matches();
pub fn requires(mut self, name: &'static str) -> Arg {
pub fn requires(mut self, name: &'r str) -> Arg<'n, 'l, 'h, 'b, 'r> {
if let Some(ref mut vec) = self.requires {
vec.push(name);
} else {
Expand All @@ -257,7 +257,7 @@ impl Arg {
/// .requires_all(
/// vec!["debug", "input"])
/// # ).get_matches();
pub fn requires_all(mut self, names: Vec<&'static str>) -> Arg {
pub fn requires_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'b, 'r> {
if let Some(ref mut vec) = self.requires {
for n in names {
vec.push(n);
Expand All @@ -282,7 +282,7 @@ impl Arg {
/// # Arg::new("conifg")
/// .takes_value(true)
/// # ).get_matches();
pub fn takes_value(mut self, tv: bool) -> Arg {
pub fn takes_value(mut self, tv: bool) -> Arg<'n, 'l, 'h, 'b, 'r> {
self.takes_value = tv;
self
}
Expand All @@ -303,7 +303,7 @@ impl Arg {
/// # Arg::new("conifg")
/// .index(1)
/// # ).get_matches();
pub fn index(mut self, idx: u8) -> Arg {
pub fn index(mut self, idx: u8) -> Arg<'n, 'l, 'h, 'b, 'r> {
self.index = Some(idx);
self
}
Expand All @@ -325,7 +325,7 @@ impl Arg {
/// # Arg::new("debug")
/// .multiple(true)
/// # ).get_matches();
pub fn multiple(mut self, multi: bool) -> Arg {
pub fn multiple(mut self, multi: bool) -> Arg<'n, 'l, 'h, 'b, 'r> {
self.multiple = multi;
self
}
Expand Down
Loading

0 comments on commit 9e8c1fb

Please sign in to comment.