1 use std::iter::Iterator;
2 use std::ops::Index;
3 use std::{ffi::OsStr, ffi::OsString};
4 
5 use crate::util::Id;
6 use crate::Arg;
7 use crate::INTERNAL_ERROR_MSG;
8 
9 #[derive(PartialEq, Eq, Debug, Clone)]
10 pub(crate) struct Key {
11     key: KeyType,
12     index: usize,
13 }
14 
15 #[derive(Default, PartialEq, Eq, Debug, Clone)]
16 pub(crate) struct MKeyMap<'help> {
17     /// All of the arguments.
18     args: Vec<Arg<'help>>,
19 
20     // Cache part:
21     /// Will be set after `_build()`.
22     keys: Vec<Key>,
23 }
24 
25 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
26 pub(crate) enum KeyType {
27     Short(char),
28     Long(OsString),
29     Position(usize),
30 }
31 
32 impl KeyType {
is_position(&self) -> bool33     pub(crate) fn is_position(&self) -> bool {
34         matches!(self, KeyType::Position(_))
35     }
36 }
37 
38 impl PartialEq<usize> for KeyType {
eq(&self, rhs: &usize) -> bool39     fn eq(&self, rhs: &usize) -> bool {
40         match self {
41             KeyType::Position(x) => x == rhs,
42             _ => false,
43         }
44     }
45 }
46 
47 impl PartialEq<&str> for KeyType {
eq(&self, rhs: &&str) -> bool48     fn eq(&self, rhs: &&str) -> bool {
49         match self {
50             KeyType::Long(l) => l == rhs,
51             _ => false,
52         }
53     }
54 }
55 
56 impl PartialEq<str> for KeyType {
eq(&self, rhs: &str) -> bool57     fn eq(&self, rhs: &str) -> bool {
58         match self {
59             KeyType::Long(l) => l == rhs,
60             _ => false,
61         }
62     }
63 }
64 
65 impl PartialEq<OsStr> for KeyType {
eq(&self, rhs: &OsStr) -> bool66     fn eq(&self, rhs: &OsStr) -> bool {
67         match self {
68             KeyType::Long(l) => l == rhs,
69             _ => false,
70         }
71     }
72 }
73 
74 impl PartialEq<char> for KeyType {
eq(&self, rhs: &char) -> bool75     fn eq(&self, rhs: &char) -> bool {
76         match self {
77             KeyType::Short(c) => c == rhs,
78             _ => false,
79         }
80     }
81 }
82 
83 impl<'help> MKeyMap<'help> {
84     /// If any arg has corresponding key in this map, we can search the key with
85     /// u64(for positional argument), char(for short flag), &str and OsString
86     /// (for long flag)
contains<K>(&self, key: K) -> bool where KeyType: PartialEq<K>,87     pub(crate) fn contains<K>(&self, key: K) -> bool
88     where
89         KeyType: PartialEq<K>,
90     {
91         self.keys.iter().any(|x| x.key == key)
92     }
93 
94     /// Reserves capacity for at least additional more elements to be inserted
reserve(&mut self, additional: usize)95     pub(crate) fn reserve(&mut self, additional: usize) {
96         self.args.reserve(additional);
97     }
98 
99     /// Push an argument in the map.
push(&mut self, new_arg: Arg<'help>)100     pub(crate) fn push(&mut self, new_arg: Arg<'help>) {
101         self.args.push(new_arg);
102     }
103 
104     /// Find the arg have corresponding key in this map, we can search the key
105     /// with u64(for positional argument), char(for short flag), &str and
106     /// OsString (for long flag)
get<K: ?Sized>(&self, key: &K) -> Option<&Arg<'help>> where KeyType: PartialEq<K>,107     pub(crate) fn get<K: ?Sized>(&self, key: &K) -> Option<&Arg<'help>>
108     where
109         KeyType: PartialEq<K>,
110     {
111         self.keys
112             .iter()
113             .find(|k| &k.key == key)
114             .map(|k| &self.args[k.index])
115     }
116 
117     /// Find out if the map have no arg.
is_empty(&self) -> bool118     pub(crate) fn is_empty(&self) -> bool {
119         self.args.is_empty()
120     }
121 
122     /// Return iterators of all keys.
keys(&self) -> impl Iterator<Item = &KeyType>123     pub(crate) fn keys(&self) -> impl Iterator<Item = &KeyType> {
124         self.keys.iter().map(|x| &x.key)
125     }
126 
127     /// Return iterators of all args.
args(&self) -> impl Iterator<Item = &Arg<'help>>128     pub(crate) fn args(&self) -> impl Iterator<Item = &Arg<'help>> {
129         self.args.iter()
130     }
131 
132     /// Return mutable iterators of all args.
args_mut<'map>(&'map mut self) -> impl Iterator<Item = &'map mut Arg<'help>>133     pub(crate) fn args_mut<'map>(&'map mut self) -> impl Iterator<Item = &'map mut Arg<'help>> {
134         self.args.iter_mut()
135     }
136 
137     /// We need a lazy build here since some we may change args after creating
138     /// the map, you can checkout who uses `args_mut`.
_build(&mut self)139     pub(crate) fn _build(&mut self) {
140         for (i, arg) in self.args.iter().enumerate() {
141             append_keys(&mut self.keys, arg, i);
142         }
143     }
144 
145     /// Remove an arg in the graph by Id, usually used by `mut_arg`. Return
146     /// `Some(arg)` if removed.
remove_by_name(&mut self, name: &Id) -> Option<Arg<'help>>147     pub(crate) fn remove_by_name(&mut self, name: &Id) -> Option<Arg<'help>> {
148         self.args
149             .iter()
150             .position(|arg| &arg.id == name)
151             // since it's a cold function, using this wouldn't hurt much
152             .map(|i| self.args.remove(i))
153     }
154 
155     /// Remove an arg based on index
remove(&mut self, index: usize) -> Arg<'help>156     pub(crate) fn remove(&mut self, index: usize) -> Arg<'help> {
157         self.args.remove(index)
158     }
159 }
160 
161 impl<'help> Index<&'_ KeyType> for MKeyMap<'help> {
162     type Output = Arg<'help>;
163 
index(&self, key: &KeyType) -> &Self::Output164     fn index(&self, key: &KeyType) -> &Self::Output {
165         self.get(key).expect(INTERNAL_ERROR_MSG)
166     }
167 }
168 
169 /// Generate key types for an specific Arg.
append_keys(keys: &mut Vec<Key>, arg: &Arg, index: usize)170 fn append_keys(keys: &mut Vec<Key>, arg: &Arg, index: usize) {
171     if let Some(pos_index) = arg.index {
172         let key = KeyType::Position(pos_index);
173         keys.push(Key { key, index });
174     } else {
175         if let Some(short) = arg.short {
176             let key = KeyType::Short(short);
177             keys.push(Key { key, index });
178         }
179         if let Some(long) = arg.long {
180             let key = KeyType::Long(OsString::from(long));
181             keys.push(Key { key, index });
182         }
183 
184         for (short, _) in arg.short_aliases.iter() {
185             let key = KeyType::Short(*short);
186             keys.push(Key { key, index });
187         }
188         for (long, _) in arg.aliases.iter() {
189             let key = KeyType::Long(OsString::from(long));
190             keys.push(Key { key, index });
191         }
192     }
193 }
194