| use std::iter::Iterator; |
| use std::ops::Index; |
| |
| use crate::builder::OsStr; |
| use crate::Arg; |
| use crate::INTERNAL_ERROR_MSG; |
| |
| #[derive(PartialEq, Eq, Debug, Clone)] |
| pub(crate) struct Key { |
| key: KeyType, |
| index: usize, |
| } |
| |
| #[derive(Default, PartialEq, Eq, Debug, Clone)] |
| pub(crate) struct MKeyMap { |
| /// All of the arguments. |
| args: Vec<Arg>, |
| |
| // Cache part: |
| /// Will be set after `_build()`. |
| keys: Vec<Key>, |
| } |
| |
| #[derive(Debug, PartialEq, Eq, Hash, Clone)] |
| pub(crate) enum KeyType { |
| Short(char), |
| Long(OsStr), |
| Position(usize), |
| } |
| |
| impl KeyType { |
| pub(crate) fn is_position(&self) -> bool { |
| matches!(self, KeyType::Position(_)) |
| } |
| } |
| |
| impl PartialEq<usize> for KeyType { |
| fn eq(&self, rhs: &usize) -> bool { |
| match self { |
| KeyType::Position(x) => x == rhs, |
| _ => false, |
| } |
| } |
| } |
| |
| impl PartialEq<&str> for KeyType { |
| fn eq(&self, rhs: &&str) -> bool { |
| match self { |
| KeyType::Long(l) => l == rhs, |
| _ => false, |
| } |
| } |
| } |
| |
| impl PartialEq<str> for KeyType { |
| fn eq(&self, rhs: &str) -> bool { |
| match self { |
| KeyType::Long(l) => l == rhs, |
| _ => false, |
| } |
| } |
| } |
| |
| impl PartialEq<OsStr> for KeyType { |
| fn eq(&self, rhs: &OsStr) -> bool { |
| match self { |
| KeyType::Long(l) => l == rhs, |
| _ => false, |
| } |
| } |
| } |
| |
| impl PartialEq<char> for KeyType { |
| fn eq(&self, rhs: &char) -> bool { |
| match self { |
| KeyType::Short(c) => c == rhs, |
| _ => false, |
| } |
| } |
| } |
| |
| impl MKeyMap { |
| /// If any arg has corresponding key in this map, we can search the key with |
| /// u64(for positional argument), char(for short flag), &str and OsString |
| /// (for long flag) |
| pub(crate) fn contains<K>(&self, key: K) -> bool |
| where |
| KeyType: PartialEq<K>, |
| { |
| self.keys.iter().any(|x| x.key == key) |
| } |
| |
| /// Push an argument in the map. |
| pub(crate) fn push(&mut self, new_arg: Arg) { |
| self.args.push(new_arg); |
| } |
| |
| /// Find the arg have corresponding key in this map, we can search the key |
| /// with u64(for positional argument), char(for short flag), &str and |
| /// OsString (for long flag) |
| pub(crate) fn get<K: ?Sized>(&self, key: &K) -> Option<&Arg> |
| where |
| KeyType: PartialEq<K>, |
| { |
| self.keys |
| .iter() |
| .find(|k| &k.key == key) |
| .map(|k| &self.args[k.index]) |
| } |
| |
| /// Return iterators of all keys. |
| pub(crate) fn keys(&self) -> impl Iterator<Item = &KeyType> { |
| self.keys.iter().map(|x| &x.key) |
| } |
| |
| /// Return iterators of all args. |
| pub(crate) fn args(&self) -> impl Iterator<Item = &Arg> { |
| self.args.iter() |
| } |
| |
| /// Return mutable iterators of all args. |
| pub(crate) fn args_mut(&mut self) -> impl Iterator<Item = &mut Arg> { |
| self.args.iter_mut() |
| } |
| |
| /// We need a lazy build here since some we may change args after creating |
| /// the map, you can checkout who uses `args_mut`. |
| pub(crate) fn _build(&mut self) { |
| for (i, arg) in self.args.iter().enumerate() { |
| append_keys(&mut self.keys, arg, i); |
| } |
| } |
| |
| /// Remove an arg in the graph by Id, usually used by `mut_arg`. Return |
| /// `Some(arg)` if removed. |
| pub(crate) fn remove_by_name(&mut self, name: &str) -> Option<Arg> { |
| self.args |
| .iter() |
| .position(|arg| arg.id == name) |
| // since it's a cold function, using this wouldn't hurt much |
| .map(|i| self.args.remove(i)) |
| } |
| } |
| |
| impl Index<&'_ KeyType> for MKeyMap { |
| type Output = Arg; |
| |
| fn index(&self, key: &KeyType) -> &Self::Output { |
| self.get(key).expect(INTERNAL_ERROR_MSG) |
| } |
| } |
| |
| /// Generate key types for an specific Arg. |
| fn append_keys(keys: &mut Vec<Key>, arg: &Arg, index: usize) { |
| if let Some(pos_index) = arg.index { |
| let key = KeyType::Position(pos_index); |
| keys.push(Key { key, index }); |
| } else { |
| if let Some(short) = arg.short { |
| let key = KeyType::Short(short); |
| keys.push(Key { key, index }); |
| } |
| if let Some(long) = arg.long.clone() { |
| let key = KeyType::Long(long.into()); |
| keys.push(Key { key, index }); |
| } |
| |
| for (short, _) in arg.short_aliases.iter() { |
| let key = KeyType::Short(*short); |
| keys.push(Key { key, index }); |
| } |
| for (long, _) in arg.aliases.iter() { |
| let key = KeyType::Long(long.into()); |
| keys.push(Key { key, index }); |
| } |
| } |
| } |