From fd61615d1a7be9d13de2114a01e2d0ad63b59274 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Thu, 23 Apr 2015 16:58:30 -0400 Subject: [PATCH] perf(matchedargs): remove unused vars and String->&str This commit increases the performance a bit by using string slices instead of owned strings. The trade off is that code previously written to handle all the argument parsing in a speratate function and return only the ArgMatches must be re-written to add a lifetime specifier: Old code 'fn handle_args<'a>() -> ArgMatches<'a>' needs another lifetime specifier added, so now 'fn handle_args<'a, 'b>() -> ArgMatches<'a, 'b>' BREAKING CHANGE --- src/app.rs | 29 +++++++++++++++-------------- src/args/argmatches.rs | 18 +++++++++--------- src/args/matchedarg.rs | 4 ++-- src/args/subcommand.rs | 10 +++++----- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/app.rs b/src/app.rs index 282b5c5f..b45e8425 100644 --- a/src/app.rs +++ b/src/app.rs @@ -41,6 +41,7 @@ use args::{ FlagBuilder, OptBuilder, PosBuilder}; pub struct App<'a, 'v, 'ab, 'u, 'h, 'ar> { // The name displayed to the user when showing version and help/usage information name: String, + name_slice: &'ar str, // A string of author(s) if desired. Displayed when showing help/usage information author: Option<&'a str>, // The version displayed to the user @@ -86,9 +87,10 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ /// let prog = App::new("myprog") /// # .get_matches(); /// ``` - pub fn new<'n>(n: &'n str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { + pub fn new(n: &'ar str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> { App { name: n.to_owned(), + name_slice: n, author: None, about: None, more_help: None, @@ -725,7 +727,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } // Used when spacing arguments and their help message when displaying help information - #[inline(always)] fn get_spaces(&self, num: usize) -> &'static str { match num { 0 => "", @@ -785,7 +786,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ // Starts the parsing process. Called on top level parent app **ONLY** then recursively calls // the real parsing function for subcommands - pub fn get_matches(mut self) -> ArgMatches<'ar> { + pub fn get_matches(mut self) -> ArgMatches<'ar, 'ar> { self.verify_positionals(); for (_,sc) in self.subcommands.iter_mut() { sc.verify_positionals(); @@ -844,7 +845,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } } - fn get_matches_from(&mut self, matches: &mut ArgMatches<'ar>, it: &mut IntoIter) { + fn get_matches_from(&mut self, matches: &mut ArgMatches<'ar, 'ar>, it: &mut IntoIter) { self.create_help_and_version(); let mut pos_only = false; @@ -951,7 +952,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ // Was an update made, or is this the first occurrence? if !done { matches.args.insert(p.name, MatchedArg{ - name: p.name.to_owned(), + // name: p.name.to_owned(), occurrences: 1, values: Some(vec![arg.clone()]), }); @@ -1008,7 +1009,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ sc.bin_name = Some(format!("{}{}{}", self.bin_name.clone().unwrap_or("".to_owned()),if self.bin_name.is_some() {" "} else {""}, sc.name.clone())); sc.get_matches_from(&mut new_matches, it); matches.subcommand = Some(Box::new(SubCommand{ - name: sc.name.clone(), + name: sc.name_slice, matches: new_matches})); } } @@ -1060,7 +1061,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } } - fn parse_long_arg(&mut self, matches: &mut ArgMatches<'ar> ,full_arg: &String) -> Option<&'ar str> { + fn parse_long_arg(&mut self, matches: &mut ArgMatches<'ar, 'ar> ,full_arg: &String) -> Option<&'ar str> { let mut arg = full_arg.trim_left_matches(|c| c == '-'); if arg == "help" && self.needs_long_help { @@ -1116,7 +1117,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } } else { matches.args.insert(v.name, MatchedArg{ - name: v.name.to_owned(), + // name: v.name.to_owned(), occurrences: if arg_val.is_some() { 1 } else { 0 }, values: if arg_val.is_some() { Some(vec![arg_val.clone().unwrap()])} else { Some(vec![]) } }); @@ -1167,7 +1168,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } if !done { matches.args.insert(v.name, MatchedArg{ - name: v.name.to_owned(), + // name: v.name.to_owned(), occurrences: 1, values: None }); @@ -1203,7 +1204,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ unreachable!(); } - fn parse_short_arg(&mut self, matches: &mut ArgMatches<'ar> ,full_arg: &String) -> Option<&'ar str> { + fn parse_short_arg(&mut self, matches: &mut ArgMatches<'ar, '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 @@ -1239,7 +1240,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } } else { matches.args.insert(v.name, MatchedArg{ - name: v.name.to_owned(), + // name: v.name.to_owned(), // occurrences will be incremented on getting a value occurrences: 0, values: Some(vec![]) @@ -1273,7 +1274,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ unreachable!(); } - fn parse_single_short_flag(&mut self, matches: &mut ArgMatches<'ar>, arg: char) -> bool { + fn parse_single_short_flag(&mut self, matches: &mut ArgMatches<'ar, '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) { @@ -1293,7 +1294,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ } if !done { matches.args.insert(v.name, MatchedArg{ - name: v.name.to_owned(), + // name: v.name.to_owned(), occurrences: 1, values: None }); @@ -1325,7 +1326,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{ false } - fn validate_blacklist(&self, matches: &ArgMatches<'ar>) { + fn validate_blacklist(&self, matches: &ArgMatches<'ar, 'ar>) { for name in self.blacklist.iter() { if matches.args.contains_key(name) { self.report_error(format!("The argument {} cannot be used with one or more of the other specified arguments", diff --git a/src/args/argmatches.rs b/src/args/argmatches.rs index c7411093..0a23c3c6 100644 --- a/src/args/argmatches.rs +++ b/src/args/argmatches.rs @@ -52,16 +52,16 @@ use args::MatchedArg; /// println!("Not printing testing lists..."); /// } /// } -pub struct ArgMatches<'a> { +pub struct ArgMatches<'n, 'a> { #[doc(hidden)] pub args: HashMap<&'a str, MatchedArg>, #[doc(hidden)] - pub subcommand: Option>>, + pub subcommand: Option>>, #[doc(hidden)] pub usage: Option } -impl<'a> ArgMatches<'a> { +impl<'n, 'a> ArgMatches<'n, 'a> { /// Creates a new instance of `ArgMatches`. This ins't called directly, but /// through the `.get_matches()` method of `App` /// @@ -72,7 +72,7 @@ impl<'a> ArgMatches<'a> { /// let matches = App::new("myprog").get_matches(); /// ``` #[doc(hidden)] - pub fn new() -> ArgMatches<'a> { + pub fn new() -> ArgMatches<'n, 'a> { ArgMatches { args: HashMap::new(), subcommand: None, @@ -96,7 +96,7 @@ impl<'a> ArgMatches<'a> { /// println!("Value for output: {}", o); /// } /// ``` - pub fn value_of<'n>(&self, name: &'n str) -> Option<&str> { + pub fn value_of<'na>(&self, name: &'na str) -> Option<&str> { if let Some(ref arg) = self.args.get(name) { if let Some(ref vals) = arg.values { if let Some(ref val) = vals.iter().nth(0) { @@ -125,7 +125,7 @@ impl<'a> ArgMatches<'a> { /// } /// } /// ``` - pub fn values_of<'n>(&'a self, name: &'n str) -> Option> { + pub fn values_of<'na>(&'a self, name: &'na str) -> Option> { if let Some(ref arg) = self.args.get(name) { if let Some(ref vals) = arg.values { return Some(vals.iter().map(|s| &s[..]).collect::>()); @@ -146,7 +146,7 @@ impl<'a> ArgMatches<'a> { /// println!("The output argument was used!"); /// } /// ``` - pub fn is_present<'n>(&self, name: &'n str) -> bool { + pub fn is_present<'na>(&self, name: &'na str) -> bool { if let Some(ref sc) = self.subcommand { if sc.name == name { return true; } } @@ -170,7 +170,7 @@ impl<'a> ArgMatches<'a> { /// println!("Debug mode kind of on"); /// } /// ``` - pub fn occurrences_of<'n>(&self, name: &'n str) -> u8 { + pub fn occurrences_of<'na>(&self, name: &'na str) -> u8 { if let Some(ref arg) = self.args.get(name) { return arg.occurrences; } @@ -190,7 +190,7 @@ impl<'a> ArgMatches<'a> { /// // Use matches as normal /// } /// ``` - pub fn subcommand_matches<'n>(&self, name: &'n str) -> Option<&ArgMatches> { + pub fn subcommand_matches<'na>(&self, name: &'na str) -> Option<&ArgMatches> { if let Some( ref sc) = self.subcommand { if sc.name != name { return None; } return Some(&sc.matches); diff --git a/src/args/matchedarg.rs b/src/args/matchedarg.rs index 8afa719d..275fb7c6 100644 --- a/src/args/matchedarg.rs +++ b/src/args/matchedarg.rs @@ -1,7 +1,7 @@ #[doc(hidden)] pub struct MatchedArg { - #[doc(hidden)] - pub name: String, + // #[doc(hidden)] + // pub name: String, #[doc(hidden)] pub occurrences: u8, #[doc(hidden)] diff --git a/src/args/subcommand.rs b/src/args/subcommand.rs index 27346fb8..33b9b9b5 100644 --- a/src/args/subcommand.rs +++ b/src/args/subcommand.rs @@ -20,12 +20,12 @@ use ArgMatches; /// .help("The configuration file to use") /// .index(1)) /// # ).get_matches(); -pub struct SubCommand<'a> { - pub name: String, - pub matches: ArgMatches<'a> +pub struct SubCommand<'n, 'a> { + pub name: &'n str, + pub matches: ArgMatches<'n, 'a> } -impl<'a> SubCommand<'a> { +impl<'n, 'a> SubCommand<'n, 'a> { /// Creates a new instance of a subcommand requiring a name. Will be displayed /// to the user when they print version or help and usage information. /// @@ -37,7 +37,7 @@ impl<'a> SubCommand<'a> { /// SubCommand::new("config") /// # ).get_matches(); /// ``` - pub fn new<'n, 'au, 'v, 'ab, 'u, 'h, 'ar>(name: &'n str) -> App<'au, 'v, 'ab, 'u, 'h, 'ar> { + pub fn new<'au, 'v, 'ab, 'u, 'h, 'ar>(name: &'ar str) -> App<'au, 'v, 'ab, 'u, 'h, 'ar> { App::new(name) } } \ No newline at end of file