mirror of
https://github.com/clap-rs/clap
synced 2024-12-15 23:32:32 +00:00
463 lines
12 KiB
Rust
463 lines
12 KiB
Rust
use build::Arg;
|
|
use std::collections::hash_map;
|
|
use std::collections::hash_map::DefaultHasher;
|
|
use std::collections::{HashMap, HashSet};
|
|
use std::ffi::OsString;
|
|
use std::hash::{Hash, Hasher};
|
|
use std::slice;
|
|
// ! rustdoc
|
|
|
|
#[derive(Default, PartialEq, Debug, Clone)]
|
|
pub struct MKeyMap<T> {
|
|
keys: HashMap<KeyType, usize>,
|
|
value_index: Vec<T>,
|
|
values: HashMap<u64, HashSet<usize>>,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
|
pub enum KeyType {
|
|
Short(char),
|
|
Long(OsString),
|
|
Position(u64),
|
|
}
|
|
|
|
impl KeyType {
|
|
pub(crate) fn is_position(&self) -> bool {
|
|
match *self {
|
|
KeyType::Position(_) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
pub(crate) fn is_short(&self) -> bool {
|
|
match *self {
|
|
KeyType::Short(_) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
pub(crate) fn is_long(&self) -> bool {
|
|
match *self {
|
|
KeyType::Long(_) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> MKeyMap<T>
|
|
where
|
|
T: Sized + Hash + PartialEq + Default + Eq,
|
|
{
|
|
pub fn new() -> Self { MKeyMap::default() }
|
|
//TODO ::from(x), ::with_capacity(n) etc
|
|
//? set theory ops?
|
|
|
|
pub fn insert(&mut self, key: KeyType, value: T) -> usize {
|
|
let index = self.push(value);
|
|
self.keys.insert(key, index);
|
|
index
|
|
}
|
|
|
|
pub fn push(&mut self, value: T) -> usize {
|
|
let index;
|
|
let mut hasher = DefaultHasher::new();
|
|
|
|
value.hash(&mut hasher);
|
|
|
|
let hash = hasher.finish();
|
|
|
|
if let Some((idx, _)) = self.values.get(&hash).and_then(|ids| {
|
|
ids.iter()
|
|
.map(|&x| (x, &self.value_index[x]))
|
|
.find(|(_i, x)| x == &&value)
|
|
}) {
|
|
debug_assert!(false, "Non-unique value found");
|
|
index = idx;
|
|
} else {
|
|
self.value_index.push(value);
|
|
index = self.value_index.len() - 1;
|
|
self.values
|
|
.entry(hash)
|
|
.and_modify(|x| {
|
|
x.insert(index);
|
|
}).or_insert({
|
|
let mut set = HashSet::new();
|
|
set.insert(index);
|
|
set
|
|
});
|
|
}
|
|
|
|
index
|
|
}
|
|
//TODO ::push_many([x, y])
|
|
|
|
pub fn insert_key(&mut self, key: KeyType, index: usize) {
|
|
if index >= self.values.len() {
|
|
panic!("Index out of bounds");
|
|
}
|
|
|
|
self.keys.insert(key, index);
|
|
}
|
|
//TODO ::insert_keyset([Long, Key2])
|
|
|
|
// ! Arg mutation functionality
|
|
|
|
pub fn get(&self, key: KeyType) -> Option<&T> {
|
|
self.keys
|
|
.get(&key)
|
|
.and_then(|&idx| self.value_index.get(idx))
|
|
}
|
|
//TODO ::get_first([KeyA, KeyB])
|
|
|
|
pub fn get_mut(&mut self, key: KeyType) -> Option<&mut T> {
|
|
if let Some(&idx) = self.keys.get(&key) {
|
|
self.value_index.get_mut(idx)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn is_empty(&self) -> bool { self.keys.is_empty() && self.values.is_empty() }
|
|
|
|
pub fn remove_by_name(&mut self, _name: &str) -> Option<T> { unimplemented!() }
|
|
|
|
pub fn remove(&mut self, _key: KeyType) -> Option<T> { unimplemented!() }
|
|
//TODO ::remove_many([KeyA, KeyB])
|
|
//? 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) { self.keys.remove(&key); }
|
|
//TODO ::remove_keys([KeyA, KeyB])
|
|
|
|
pub fn keys(&self) -> Keys<usize> {
|
|
Keys {
|
|
iter: self.keys.keys(),
|
|
}
|
|
}
|
|
|
|
pub fn values(&self) -> Values<T> {
|
|
Values {
|
|
iter: self.value_index.iter(),
|
|
}
|
|
}
|
|
|
|
pub fn values_mut(&mut self) -> ValuesMut<T> {
|
|
ValuesMut {
|
|
iter: self.value_index.iter_mut(),
|
|
}
|
|
}
|
|
|
|
pub fn iter(&self) -> Iter<T> {
|
|
Iter {
|
|
map: self,
|
|
keys: self.keys(),
|
|
}
|
|
}
|
|
}
|
|
|
|
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>,
|
|
}
|
|
|
|
impl<'a, V> Iterator for Keys<'a, V> {
|
|
type Item = &'a KeyType;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> { self.iter.next() }
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Values<'a, V: 'a> {
|
|
iter: slice::Iter<'a, V>,
|
|
}
|
|
|
|
impl<'a, V> Iterator for Values<'a, V> {
|
|
type Item = &'a V;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> { self.iter.next() }
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ValuesMut<'a, V: 'a> {
|
|
iter: slice::IterMut<'a, V>,
|
|
}
|
|
|
|
impl<'a, V> Iterator for ValuesMut<'a, V> {
|
|
type Item = &'a mut V;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> { self.iter.next() }
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Iter<'c, T>
|
|
where
|
|
T: 'c,
|
|
{
|
|
map: &'c MKeyMap<T>,
|
|
keys: Keys<'c, usize>,
|
|
}
|
|
|
|
impl<'c, T> Iterator for Iter<'c, T>
|
|
where
|
|
T: 'c + Sized + Hash + PartialEq + Default + Eq,
|
|
{
|
|
type Item = (&'c KeyType, &'c T);
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if let Some(key) = self.keys.next() {
|
|
Some((key, self.map.get(key.clone()).unwrap()))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use self::KeyType::*;
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn get_some_value() {
|
|
let mut map: MKeyMap<Arg> = MKeyMap::new();
|
|
|
|
map.insert(Long(OsString::from("One")), Arg::with_name("Value1"));
|
|
|
|
assert_eq!(
|
|
map.get(Long(OsString::from("One"))),
|
|
Some(&Arg::with_name("Value1"))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn get_none_value() {
|
|
let mut map: MKeyMap<Arg> = MKeyMap::new();
|
|
|
|
map.insert(Long(OsString::from("One")), Arg::with_name("Value1"));
|
|
map.get(Long(OsString::from("Two")));
|
|
|
|
assert_eq!(map.get(Long(OsString::from("Two"))), None);
|
|
}
|
|
|
|
// #[test]
|
|
// fn insert_delete_value() {
|
|
// let mut map = MKeyMap::new();
|
|
// map.insert("One", clap::Arg::with_name("Value1"));
|
|
// assert_eq!(map.remove("One"), Some(clap::Arg::with_name("Value1")));
|
|
// assert!(map.is_empty());
|
|
// }
|
|
|
|
#[test]
|
|
fn insert_duplicate_key() {
|
|
let mut map: MKeyMap<Arg> = MKeyMap::new();
|
|
|
|
map.insert(Long(OsString::from("One")), Arg::with_name("Value1"));
|
|
|
|
assert_eq!(
|
|
map.insert(Long(OsString::from("One")), Arg::with_name("Value2")),
|
|
1
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn insert_duplicate_value() {
|
|
let mut map: MKeyMap<Arg> = MKeyMap::new();
|
|
|
|
map.insert(Long(OsString::from("One")), Arg::with_name("Value1"));
|
|
|
|
let orig_len = map.values.len();
|
|
|
|
map.insert(Long(OsString::from("Two")), Arg::with_name("Value1"));
|
|
|
|
assert_eq!(map.values.len(), orig_len);
|
|
assert_eq!(
|
|
map.get(Long(OsString::from("One"))),
|
|
map.get(Long(OsString::from("Two")))
|
|
);
|
|
}
|
|
|
|
// #[test]
|
|
// fn insert_delete_none() {
|
|
// let mut map = MKeyMap::new();
|
|
// map.insert("One", clap::Arg::with_name("Value1"));
|
|
// assert_eq!(map.remove("Two"), None);
|
|
// assert!(!map.is_empty());
|
|
// assert_eq!(map.get("One"), Some(clap::Arg::with_name("Value1")));
|
|
// }
|
|
|
|
#[test]
|
|
fn insert_multiple_keys() {
|
|
let mut map: MKeyMap<Arg> = MKeyMap::new();
|
|
let index = map.insert(Long(OsString::from("One")), Arg::with_name("Value1"));
|
|
|
|
map.insert_key(Long(OsString::from("Two")), index);
|
|
|
|
assert_eq!(
|
|
map.get(Long(OsString::from("One"))),
|
|
map.get(Long(OsString::from("Two")))
|
|
);
|
|
assert_eq!(map.values.len(), 1);
|
|
}
|
|
|
|
// #[test]
|
|
// fn insert_by_name() {
|
|
// let mut map: MKeyMap<Arg> = MKeyMap::new();
|
|
// let index = map.insert(Long(OsString::from("One")), Arg::with_name("Value1"));
|
|
|
|
// map.insert_key_by_name(Long(OsString::from("Two")), "Value1");
|
|
|
|
// assert_eq!(
|
|
// map.get(Long(OsString::from("One"))),
|
|
// map.get(Long(OsString::from("Two")))
|
|
// );
|
|
// assert_eq!(map.values.len(), 1);
|
|
// }
|
|
|
|
#[test]
|
|
fn get_mutable() {
|
|
let mut map: MKeyMap<Arg> = MKeyMap::new();
|
|
|
|
map.insert(Long(OsString::from("One")), Arg::with_name("Value1"));
|
|
|
|
assert_eq!(
|
|
map.get_mut(Long(OsString::from("One"))),
|
|
Some(&mut Arg::with_name("Value1"))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn remove_key() {
|
|
let mut map: MKeyMap<Arg> = MKeyMap::new();
|
|
let index = map.insert(Long(OsString::from("One")), Arg::with_name("Value1"));
|
|
|
|
map.insert_key(Long(OsString::from("Two")), index);
|
|
map.remove_key(Long(OsString::from("One")));
|
|
|
|
assert_eq!(map.keys.len(), 1);
|
|
assert_eq!(map.values.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn iter_keys() {
|
|
let mut map: MKeyMap<Arg> = MKeyMap::new();
|
|
|
|
map.insert(Long(OsString::from("One")), Arg::with_name("Value1"));
|
|
map.insert(Long(OsString::from("Two")), Arg::with_name("Value2"));
|
|
map.insert(Position(1), Arg::with_name("Value3"));
|
|
|
|
let iter = map.keys().cloned();
|
|
let mut ground_truth = HashSet::new();
|
|
|
|
ground_truth.insert(Long(OsString::from("One")));
|
|
ground_truth.insert(Long(OsString::from("Two")));
|
|
ground_truth.insert(Position(1));
|
|
|
|
assert_eq!(
|
|
ground_truth.symmetric_difference(&iter.collect()).count(),
|
|
0
|
|
);
|
|
}
|
|
}
|