Arg-specific API for MKeyMap

This commit is contained in:
Alena Yuryeva 2018-08-01 20:33:55 +05:00 committed by Kevin K
parent a75b67838e
commit 87c88d6054
No known key found for this signature in database
GPG key ID: 2E39D46AABC94DDD
6 changed files with 127 additions and 36 deletions

3
.gitignore vendored
View file

@ -26,3 +26,6 @@ Cargo.lock
.vscode/*
.idea/*
clap-rs.iml
# Auxiliary files
test-results.test

View file

@ -679,7 +679,7 @@ impl<'a, 'b> App<'a, 'b> {
// @TODO @perf @p4 @v3-beta: maybe extend_from_slice would be possible and perform better?
// But that may also not let us do `&["-a 'some'", "-b 'other']` because of not Into<Arg>
for arg in args.into_iter() {
self.args.push(arg.into());
self.args.make_entries(arg.into());
}
self
}
@ -988,19 +988,8 @@ impl<'a, 'b> App<'a, 'b> {
where
F: FnOnce(Arg<'a, 'b>) -> Arg<'a, 'b>,
{
// let i = self
// .args
// .values()
// .enumerate()
// .filter_map(|(i, a)| if a.name == arg { Some(i) } else { None })
// .next();
let a = if let Some(x) = self.args.remove_by_name(arg) {
f(x)
} else {
let mut x = Arg::with_name(arg);
f(x)
};
self.args.push(a);
self.args.mut_arg(arg, f);
self
}
@ -1542,7 +1531,7 @@ impl<'a, 'b> App<'a, 'b> {
// we have to set short manually because we're dealing with char's
arg.short = self.help_short;
self.args.push(arg);
self.args.make_entries(arg);
} else {
self.settings.unset(AppSettings::NeedsLongHelp);
}
@ -1557,7 +1546,7 @@ impl<'a, 'b> App<'a, 'b> {
.help(self.version_message.unwrap_or("Prints version information"));
// we have to set short manually because we're dealing with char's
arg.short = self.version_short;
self.args.push(arg);
self.args.make_entries(arg);
} else {
self.settings.unset(AppSettings::NeedsLongVersion);
}
@ -2030,7 +2019,7 @@ impl<'a, 'b> App<'a, 'b> {
note = "Use `App::arg(Arg::from(&str)` instead. Will be removed in v3.0-beta"
)]
pub fn arg_from_usage(mut self, usage: &'a str) -> Self {
self.args.push(Arg::from(usage));
self.args.make_entries(Arg::from(usage));
self
}
@ -2045,7 +2034,7 @@ impl<'a, 'b> App<'a, 'b> {
if l.is_empty() {
continue;
}
self.args.push(Arg::from(l));
self.args.make_entries(Arg::from(l));
}
self
}

View file

@ -1,6 +1,6 @@
// Std
use std::io::Write;
use std::ffi::OsStr;
use std::io::Write;
// Internal
use build::{App, Arg};
@ -182,7 +182,9 @@ complete -F _{name} -o bashdefault -o default {name}
shorts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s)),
// Handles aliases too
// error-handling?
longs = longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l.to_str().unwrap())),
longs = longs!(p).fold(String::new(), |acc, l| {
format!("{} --{}", acc, l.to_str().unwrap())
}),
pos = positionals!(p).fold(String::new(), |acc, p| format!("{} {}", acc, p)),
// Handles aliases too
subcmds = sc_names!(p).fold(String::new(), |acc, s| format!("{} {}", acc, s))

View file

@ -466,7 +466,7 @@ macro_rules! crate_authors {
struct CargoAuthors {
__private_field: (),
};
impl Deref for CargoAuthors {
type Target = str;

View file

@ -4,6 +4,7 @@ use std::collections::hash_map::DefaultHasher;
use std::collections::{HashMap, HashSet};
use std::ffi::OsString;
use std::hash::{Hash, Hasher};
use std::mem;
use std::slice;
// ! rustdoc
@ -18,7 +19,7 @@ pub struct MKeyMap<T> {
pub enum KeyType {
Short(char),
Long(OsString),
Position(usize),
Position(u64),
}
impl<T> MKeyMap<T>
@ -77,16 +78,6 @@ where
}
//TODO ::insert_keyset([Long, Key2])
// pub fn insert_key_by_name(&mut self, key: KeyType, name: &str) {
// let index = self
// .value_index
// .iter()
// .position(|x| x.name == name)
// .expect("No such name found");
// self.keys.insert(key, index);
// }
// ! Arg mutation functionality
pub fn get(&self, key: KeyType) -> Option<&T> {
@ -113,7 +104,7 @@ where
//? probably shouldn't add a possibility for removal?
//? or remove by replacement by some dummy object, so the order is preserved
pub fn remove_key(&mut self, key: KeyType) { unimplemented!() }
pub fn remove_key(&mut self, key: KeyType) { self.keys.remove(&key); }
//TODO ::remove_keys([KeyA, KeyB])
pub fn keys(&self) -> Keys<usize> {
@ -142,6 +133,113 @@ where
}
}
impl<'a, 'b> MKeyMap<Arg<'a, 'b>> {
pub fn insert_key_by_name(&mut self, key: KeyType, name: &str) {
let index = self.find_by_name(name);
self.keys.insert(key, index);
}
pub fn make_entries(&mut self, arg: Arg<'a, 'b>) -> usize {
let short = arg.short.map(|c| KeyType::Short(c));
let positional = arg.index.map(|n| KeyType::Position(n));
let mut longs = arg
.aliases
.clone()
.map(|v| {
v.iter()
.map(|(n, _)| KeyType::Long(OsString::from(n)))
.collect()
})
.unwrap_or(Vec::new());
longs.extend(arg.long.map(|l| KeyType::Long(OsString::from(l))));
let index = self.push(arg);
short.map(|s| self.insert_key(s, index));
positional.map(|p| self.insert_key(p, index));
longs.into_iter().map(|l| self.insert_key(l, index)).count();
index
}
pub fn make_entries_by_index(&mut self, index: usize) {
let short;
let positional;
let mut longs;
{
let arg = &self.value_index[index];
short = arg.short.map(|c| KeyType::Short(c));
positional = arg.index.map(|n| KeyType::Position(n));
longs = arg
.aliases
.clone()
.map(|v| {
v.iter()
.map(|(n, _)| KeyType::Long(OsString::from(n)))
.collect()
})
.unwrap_or(Vec::new());
longs.extend(arg.long.map(|l| KeyType::Long(OsString::from(l))));
}
short.map(|s| self.insert_key(s, index));
positional.map(|p| self.insert_key(p, index));
longs.into_iter().map(|l| self.insert_key(l, index)).count();
}
pub fn mut_arg<F>(&mut self, name: &str, f: F)
where
F: FnOnce(Arg<'a, 'b>) -> Arg<'a, 'b>,
{
let index = self.find_by_name(name);
let new_arg = f(self.value_index[index].clone());
let value_key = self
.values
.iter()
.filter(|(_, v)| v.contains(&index))
.map(|(k, _)| k)
.next()
.map(|&x| x);
value_key.map(|k| {
self.values.entry(k).and_modify(|v| {
v.remove(&index);
})
});
let mut hasher = DefaultHasher::new();
new_arg.hash(&mut hasher);
let hash = hasher.finish();
self.values
.entry(hash)
.and_modify(|x| {
x.insert(index);
})
.or_insert({
let mut set = HashSet::new();
set.insert(index);
set
});
self.value_index.push(new_arg);
self.value_index.swap_remove(index);
self.make_entries_by_index(index);
}
pub fn find_by_name(&mut self, name: &str) -> usize {
self.value_index
.iter()
.position(|x| x.name == name)
.expect("No such name found")
}
}
#[derive(Debug)]
pub struct Keys<'a, V: 'a> {
iter: hash_map::Keys<'a, KeyType, V>,
@ -218,7 +316,6 @@ mod tests {
}
#[test]
#[should_panic]
fn get_none_value() {
let mut map: MKeyMap<Arg> = MKeyMap::new();

View file

@ -133,7 +133,7 @@ where
.count();
assert!(
highest_idx == num_p,
highest_idx == num_p as u64,
"Found positional argument whose index is {} but there \
are only {} positional arguments defined",
highest_idx,
@ -301,7 +301,7 @@ where
let mut key: Vec<(KeyType, usize)> = Vec::new();
for (i, a) in self.app.args.values().enumerate() {
if let Some(ref index) = a.index {
key.push((KeyType::Position((*index) as usize), i));
key.push((KeyType::Position(*index), i));
} else {
if let Some(ref c) = a.short {
key.push((KeyType::Short(*c), i));