Skip to content

Commit 9e8c1fb

Browse files
committed
feat(arg): allow lifetimes other than 'static in arguments
1 parent 76f015e commit 9e8c1fb

File tree

7 files changed

+95
-96
lines changed

7 files changed

+95
-96
lines changed

src/app.rs

+32-32
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use args::{PosArg, PosBuilder};
3636
///
3737
/// // Your pogram logic starts here...
3838
/// ```
39-
pub struct App<'a, 'v, 'ab, 'u> {
39+
pub struct App<'a, 'v, 'ab, 'u, 'ar> {
4040
// The name displayed to the user when showing version and help/usage information
4141
name: String,
4242
// A string of author(s) if desired. Displayed when showing help/usage information
@@ -45,26 +45,26 @@ pub struct App<'a, 'v, 'ab, 'u> {
4545
version: Option<&'v str>,
4646
// A brief explaination of the program that gets displayed to the user when shown help/usage information
4747
about: Option<&'ab str>,
48-
flags: HashMap<&'static str, FlagBuilder>,
49-
opts: HashMap<&'static str, OptBuilder>,
50-
positionals_idx: BTreeMap<u8, PosBuilder>,
51-
subcommands: HashMap<String, App<'a, 'v, 'ab, 'u>>,
48+
flags: HashMap<&'ar str, FlagBuilder<'ar>>,
49+
opts: HashMap<&'ar str, OptBuilder<'ar>>,
50+
positionals_idx: BTreeMap<u8, PosBuilder<'ar>>,
51+
subcommands: HashMap<String, App<'a, 'v, 'ab, 'u, 'ar>>,
5252
needs_long_help: bool,
5353
needs_long_version: bool,
5454
needs_short_help: bool,
5555
needs_short_version: bool,
5656
needs_subcmd_help: bool,
57-
required: HashSet<&'static str>,
58-
arg_list: HashSet<&'static str>,
57+
required: HashSet<&'ar str>,
58+
arg_list: HashSet<&'ar str>,
5959
short_list: HashSet<char>,
60-
long_list: HashSet<&'static str>,
61-
blacklist: HashSet<&'static str>,
60+
long_list: HashSet<&'ar str>,
61+
blacklist: HashSet<&'ar str>,
6262
usage_str: Option<&'u str>,
6363
bin_name: Option<String>
6464

6565
}
6666

67-
impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
67+
impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
6868
/// Creates a new instance of an application requiring a name (such as the binary). Will be displayed
6969
/// to the user when they print version or help and usage information.
7070
///
@@ -75,7 +75,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
7575
/// let prog = App::new("myprog")
7676
/// # .get_matches();
7777
/// ```
78-
pub fn new<'n>(n: &'n str) -> App<'a, 'v, 'ab, 'u> {
78+
pub fn new<'n>(n: &'n str) -> App<'a, 'v, 'ab, 'u, 'ar> {
7979
App {
8080
name: n.to_owned(),
8181
author: None,
@@ -110,7 +110,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
110110
/// .author("Kevin <[email protected]>")
111111
/// # .get_matches();
112112
/// ```
113-
pub fn author(mut self, a: &'a str) -> App<'a, 'v, 'ab, 'u> {
113+
pub fn author(mut self, a: &'a str) -> App<'a, 'v, 'ab, 'u, 'ar> {
114114
self.author = Some(a);
115115
self
116116
}
@@ -125,7 +125,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
125125
/// .about("Does really amazing things to great people")
126126
/// # .get_matches();
127127
/// ```
128-
pub fn about(mut self, a: &'ab str) -> App<'a, 'v, 'ab, 'u > {
128+
pub fn about(mut self, a: &'ab str) -> App<'a, 'v, 'ab, 'u, 'ar> {
129129
self.about = Some(a);
130130
self
131131
}
@@ -140,7 +140,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
140140
/// .version("v0.1.24")
141141
/// # .get_matches();
142142
/// ```
143-
pub fn version(mut self, v: &'v str) -> App<'a, 'v, 'ab, 'u> {
143+
pub fn version(mut self, v: &'v str) -> App<'a, 'v, 'ab, 'u, 'ar> {
144144
self.version = Some(v);
145145
self
146146
}
@@ -162,7 +162,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
162162
/// .usage("myapp [-clDas] <some_file>")
163163
/// # .get_matches();
164164
/// ```
165-
pub fn usage(mut self, u: &'u str) -> App<'a, 'v, 'ab, 'u> {
165+
pub fn usage(mut self, u: &'u str) -> App<'a, 'v, 'ab, 'u, 'ar> {
166166
self.usage_str = Some(u);
167167
self
168168
}
@@ -180,7 +180,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
180180
/// )
181181
/// # .get_matches();
182182
/// ```
183-
pub fn arg(mut self, a: Arg) -> App<'a, 'v, 'ab, 'u> {
183+
pub fn arg<'l, 'h, 'b, 'r>(mut self, a: Arg<'ar, 'ar, 'ar, 'ar, 'ar>) -> App<'a, 'v, 'ab, 'u, 'ar> {
184184
if self.arg_list.contains(a.name) {
185185
panic!("Argument name must be unique, \"{}\" is already in use", a.name);
186186
} else {
@@ -289,7 +289,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
289289
/// Arg::new("debug").short("d")])
290290
/// # .get_matches();
291291
/// ```
292-
pub fn args(mut self, args: Vec<Arg>) -> App<'a, 'v, 'ab, 'u> {
292+
pub fn args(mut self, args: Vec<Arg<'ar, 'ar, 'ar, 'ar, 'ar>>) -> App<'a, 'v, 'ab, 'u, 'ar> {
293293
for arg in args.into_iter() {
294294
self = self.arg(arg);
295295
}
@@ -314,7 +314,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
314314
/// // Additional subcommand configuration goes here, such as arguments...
315315
/// # .get_matches();
316316
/// ```
317-
pub fn subcommand(mut self, subcmd: App<'a, 'v, 'ab, 'u>) -> App<'a, 'v, 'ab, 'u> {
317+
pub fn subcommand(mut self, subcmd: App<'a, 'v, 'ab, 'u, 'ar>) -> App<'a, 'v, 'ab, 'u, 'ar> {
318318
if subcmd.name == "help" { self.needs_subcmd_help = false; }
319319
self.subcommands.insert(subcmd.name.clone(), subcmd);
320320
self
@@ -333,7 +333,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
333333
/// SubCommand::new("debug").about("Controls debug functionality")])
334334
/// # .get_matches();
335335
/// ```
336-
pub fn subcommands(mut self, subcmds: Vec<App<'a, 'v, 'ab, 'u>>) -> App<'a, 'v, 'ab, 'u> {
336+
pub fn subcommands(mut self, subcmds: Vec<App<'a, 'v, 'ab, 'u, 'ar>>) -> App<'a, 'v, 'ab, 'u, 'ar> {
337337
for subcmd in subcmds.into_iter() {
338338
self = self.subcommand(subcmd);
339339
}
@@ -449,7 +449,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
449449
if quit { env::set_exit_status(1); self.exit(); }
450450
}
451451

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

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

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

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

527527
matches.positionals.insert(p.name, PosArg{
528-
name: p.name,
528+
name: p.name.to_owned(),
529529
value: arg.clone(),
530530
});
531531

@@ -616,7 +616,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
616616
}
617617
}
618618

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

622622
if arg == "help" && self.needs_long_help {
@@ -656,7 +656,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
656656
}
657657
} else {
658658
matches.opts.insert(v.name, OptArg{
659-
name: v.name,
659+
name: v.name.to_owned(),
660660
occurrences: 1,
661661
values: if arg_val.is_some() { vec![arg_val.clone().unwrap()]} else {vec![]}
662662
});
@@ -706,7 +706,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
706706
}
707707
if !done {
708708
matches.flags.insert(v.name, FlagArg{
709-
name: v.name,
709+
name: v.name.to_owned(),
710710
occurrences: 1
711711
});
712712
}
@@ -742,7 +742,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
742742
unreachable!();
743743
}
744744

745-
fn parse_short_arg(&mut self, matches: &mut ArgMatches ,full_arg: &String) -> Option<&'static str> {
745+
fn parse_short_arg(&mut self, matches: &mut ArgMatches<'ar> ,full_arg: &String) -> Option<&'ar str> {
746746
let arg = &full_arg[..].trim_left_matches(|c| c == '-');
747747
if arg.len() > 1 {
748748
// Multiple flags using short i.e. -bgHlS
@@ -778,7 +778,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
778778
}
779779
} else {
780780
matches.opts.insert(v.name, OptArg{
781-
name: v.name,
781+
name: v.name.to_owned(),
782782
occurrences: 1,
783783
values: vec![]
784784
});
@@ -811,7 +811,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
811811
unreachable!();
812812
}
813813

814-
fn parse_single_short_flag(&mut self, matches: &mut ArgMatches, arg: char) -> bool {
814+
fn parse_single_short_flag(&mut self, matches: &mut ArgMatches<'ar>, arg: char) -> bool {
815815
for v in self.flags.values().filter(|&v| v.short.is_some()).filter(|&v| v.short.unwrap() == arg) {
816816
// Ensure this flag isn't on the mutually excludes list
817817
if self.blacklist.contains(v.name) {
@@ -831,7 +831,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
831831
}
832832
if !done {
833833
matches.flags.insert(v.name, FlagArg{
834-
name: v.name,
834+
name: v.name.to_owned(),
835835
occurrences: 1
836836
});
837837
}
@@ -864,7 +864,7 @@ impl<'a, 'v, 'ab, 'u> App<'a, 'v, 'ab, 'u>{
864864
false
865865
}
866866

867-
fn validate_blacklist(&self, matches: &ArgMatches) {
867+
fn validate_blacklist(&self, matches: &ArgMatches<'ar>) {
868868
for name in self.blacklist.iter() {
869869
if matches.flags.contains_key(name) {
870870
self.report_error(format!("The argument {} is mutually exclusive with one or more other arguments",

src/args/arg.rs

+19-19
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818
/// .takes_value(true)
1919
/// .help("Provides a config file to myprog")
2020
/// # ).get_matches();
21-
pub struct Arg {
21+
pub struct Arg<'n, 'l, 'h, 'b, 'r> {
2222
/// The unique name of the argument, required
23-
pub name: &'static str,
23+
pub name: &'n str,
2424
/// The short version (i.e. single character) of the argument, no preceding `-`
2525
/// **NOTE:** `short` is mutually exclusive with `index`
2626
pub short: Option<char>,
2727
/// The long version of the flag (i.e. word) without the preceding `--`
2828
/// **NOTE:** `long` is mutually exclusive with `index`
29-
pub long: Option<&'static str>,
29+
pub long: Option<&'l str>,
3030
/// The string of text that will displayed to the user when the application's
3131
/// `help` text is displayed
32-
pub help: Option<&'static str>,
32+
pub help: Option<&'h str>,
3333
/// If this is a required by default when using the command line program
3434
/// i.e. a configuration file that's required for the program to function
3535
/// **NOTE:** required by default means, it is required *until* mutually
@@ -46,13 +46,13 @@ pub struct Arg {
4646
/// I.e. `-v -v -v` or `-vvv`
4747
pub multiple: bool,
4848
/// A list of names for other arguments that *may not* be used with this flag
49-
pub blacklist: Option<Vec<&'static str>>,
49+
pub blacklist: Option<Vec<&'b str>>,
5050
/// A list of names of other arguments that are *required* to be used when
5151
/// this flag is used
52-
pub requires: Option<Vec<&'static str>>
52+
pub requires: Option<Vec<&'r str>>
5353
}
5454

55-
impl Arg {
55+
impl<'n, 'l, 'h, 'b, 'r> Arg<'n, 'l, 'h, 'b, 'r> {
5656
/// Creates a new instace of `Arg` using a unique string name.
5757
/// The name will be used by the library consumer to get information about
5858
/// whether or not the argument was used at runtime.
@@ -70,7 +70,7 @@ impl Arg {
7070
/// Arg::new("conifg")
7171
/// # .short("c")
7272
/// # ).get_matches();
73-
pub fn new(n: &'static str) -> Arg {
73+
pub fn new(n: &'n str) -> Arg<'n, 'l, 'h, 'b, 'r> {
7474
Arg {
7575
name: n,
7676
short: None,
@@ -104,7 +104,7 @@ impl Arg {
104104
/// # Arg::new("conifg")
105105
/// .short("c")
106106
/// # ).get_matches();
107-
pub fn short(mut self, s: &'static str) -> Arg {
107+
pub fn short(mut self, s: &str) -> Arg<'n, 'l, 'h, 'b, 'r> {
108108
self.short = s.trim_left_matches(|c| c == '-').chars().nth(0);
109109
self
110110
}
@@ -128,7 +128,7 @@ impl Arg {
128128
/// # Arg::new("conifg")
129129
/// .long("config")
130130
/// # ).get_matches();
131-
pub fn long(mut self, l: &'static str) -> Arg {
131+
pub fn long(mut self, l: &'l str) -> Arg<'n, 'l, 'h, 'b, 'r> {
132132
self.long = Some(l.trim_left_matches(|c| c == '-'));
133133
self
134134
}
@@ -145,7 +145,7 @@ impl Arg {
145145
/// # Arg::new("conifg")
146146
/// .help("The config file used by the myprog")
147147
/// # ).get_matches();
148-
pub fn help(mut self, h: &'static str) -> Arg {
148+
pub fn help(mut self, h: &'h str) -> Arg<'n, 'l, 'h, 'b, 'r> {
149149
self.help = Some(h);
150150
self
151151
}
@@ -168,7 +168,7 @@ impl Arg {
168168
/// # Arg::new("conifg")
169169
/// .required(true)
170170
/// # ).get_matches();
171-
pub fn required(mut self, r: bool) -> Arg {
171+
pub fn required(mut self, r: bool) -> Arg<'n, 'l, 'h, 'b, 'r> {
172172
self.required = r;
173173
self
174174
}
@@ -187,7 +187,7 @@ impl Arg {
187187
/// # let myprog = App::new("myprog").arg(Arg::new("conifg")
188188
/// .mutually_excludes("debug")
189189
/// # ).get_matches();
190-
pub fn mutually_excludes(mut self, name: &'static str) -> Arg {
190+
pub fn mutually_excludes(mut self, name: &'b str) -> Arg<'n, 'l, 'h, 'b, 'r> {
191191
if let Some(ref mut vec) = self.blacklist {
192192
vec.push(name);
193193
} else {
@@ -211,7 +211,7 @@ impl Arg {
211211
/// .mutually_excludes_all(
212212
/// vec!["debug", "input"])
213213
/// # ).get_matches();
214-
pub fn mutually_excludes_all(mut self, names: Vec<&'static str>) -> Arg {
214+
pub fn mutually_excludes_all(mut self, names: Vec<&'b str>) -> Arg<'n, 'l, 'h, 'b, 'r> {
215215
if let Some(ref mut vec) = self.blacklist {
216216
for n in names {
217217
vec.push(n);
@@ -234,7 +234,7 @@ impl Arg {
234234
/// # let myprog = App::new("myprog").arg(Arg::new("conifg")
235235
/// .requires("debug")
236236
/// # ).get_matches();
237-
pub fn requires(mut self, name: &'static str) -> Arg {
237+
pub fn requires(mut self, name: &'r str) -> Arg<'n, 'l, 'h, 'b, 'r> {
238238
if let Some(ref mut vec) = self.requires {
239239
vec.push(name);
240240
} else {
@@ -257,7 +257,7 @@ impl Arg {
257257
/// .requires_all(
258258
/// vec!["debug", "input"])
259259
/// # ).get_matches();
260-
pub fn requires_all(mut self, names: Vec<&'static str>) -> Arg {
260+
pub fn requires_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'b, 'r> {
261261
if let Some(ref mut vec) = self.requires {
262262
for n in names {
263263
vec.push(n);
@@ -282,7 +282,7 @@ impl Arg {
282282
/// # Arg::new("conifg")
283283
/// .takes_value(true)
284284
/// # ).get_matches();
285-
pub fn takes_value(mut self, tv: bool) -> Arg {
285+
pub fn takes_value(mut self, tv: bool) -> Arg<'n, 'l, 'h, 'b, 'r> {
286286
self.takes_value = tv;
287287
self
288288
}
@@ -303,7 +303,7 @@ impl Arg {
303303
/// # Arg::new("conifg")
304304
/// .index(1)
305305
/// # ).get_matches();
306-
pub fn index(mut self, idx: u8) -> Arg {
306+
pub fn index(mut self, idx: u8) -> Arg<'n, 'l, 'h, 'b, 'r> {
307307
self.index = Some(idx);
308308
self
309309
}
@@ -325,7 +325,7 @@ impl Arg {
325325
/// # Arg::new("debug")
326326
/// .multiple(true)
327327
/// # ).get_matches();
328-
pub fn multiple(mut self, multi: bool) -> Arg {
328+
pub fn multiple(mut self, multi: bool) -> Arg<'n, 'l, 'h, 'b, 'r> {
329329
self.multiple = multi;
330330
self
331331
}

0 commit comments

Comments
 (0)