nautilus_core/
collections.rs1use std::{
19 collections::{HashMap, HashSet},
20 fmt::{Debug, Display},
21 hash::Hash,
22};
23
24use ustr::Ustr;
25
26pub trait SetLike {
28 type Item: Hash + Eq + Display + Clone;
30
31 fn contains(&self, item: &Self::Item) -> bool;
33 fn is_empty(&self) -> bool;
35}
36
37impl<T, S> SetLike for HashSet<T, S>
38where
39 T: Eq + Hash + Display + Clone,
40 S: std::hash::BuildHasher,
41{
42 type Item = T;
43
44 #[inline]
45 fn contains(&self, v: &T) -> bool {
46 Self::contains(self, v)
47 }
48
49 #[inline]
50 fn is_empty(&self) -> bool {
51 Self::is_empty(self)
52 }
53}
54
55impl<T, S> SetLike for indexmap::IndexSet<T, S>
56where
57 T: Eq + Hash + Display + Clone,
58 S: std::hash::BuildHasher,
59{
60 type Item = T;
61
62 #[inline]
63 fn contains(&self, v: &T) -> bool {
64 Self::contains(self, v)
65 }
66
67 #[inline]
68 fn is_empty(&self) -> bool {
69 Self::is_empty(self)
70 }
71}
72
73impl<T, S> SetLike for ahash::AHashSet<T, S>
74where
75 T: Eq + Hash + Display + Clone,
76 S: std::hash::BuildHasher,
77{
78 type Item = T;
79
80 #[inline]
81 fn contains(&self, v: &T) -> bool {
82 self.get(v).is_some()
83 }
84
85 #[inline]
86 fn is_empty(&self) -> bool {
87 self.len() == 0
88 }
89}
90
91pub trait MapLike {
93 type Key: Hash + Eq + Display + Clone;
95 type Value: Debug;
97
98 fn contains_key(&self, key: &Self::Key) -> bool;
100 fn is_empty(&self) -> bool;
102}
103
104impl<K, V, S> MapLike for HashMap<K, V, S>
105where
106 K: Eq + Hash + Display + Clone,
107 V: Debug,
108 S: std::hash::BuildHasher,
109{
110 type Key = K;
111 type Value = V;
112
113 #[inline]
114 fn contains_key(&self, k: &K) -> bool {
115 self.contains_key(k)
116 }
117
118 #[inline]
119 fn is_empty(&self) -> bool {
120 self.is_empty()
121 }
122}
123
124impl<K, V, S> MapLike for indexmap::IndexMap<K, V, S>
125where
126 K: Eq + Hash + Display + Clone,
127 V: Debug,
128 S: std::hash::BuildHasher,
129{
130 type Key = K;
131 type Value = V;
132
133 #[inline]
134 fn contains_key(&self, k: &K) -> bool {
135 self.get(k).is_some()
136 }
137
138 #[inline]
139 fn is_empty(&self) -> bool {
140 self.is_empty()
141 }
142}
143
144impl<K, V, S> MapLike for ahash::AHashMap<K, V, S>
145where
146 K: Eq + Hash + Display + Clone,
147 V: Debug,
148 S: std::hash::BuildHasher,
149{
150 type Key = K;
151 type Value = V;
152
153 #[inline]
154 fn contains_key(&self, k: &K) -> bool {
155 self.get(k).is_some()
156 }
157
158 #[inline]
159 fn is_empty(&self) -> bool {
160 self.len() == 0
161 }
162}
163
164#[must_use]
166pub fn into_ustr_vec<I, T>(iter: I) -> Vec<Ustr>
167where
168 I: IntoIterator<Item = T>,
169 T: AsRef<str>,
170{
171 let iter = iter.into_iter();
172 let (lower, _) = iter.size_hint();
173 let mut result = Vec::with_capacity(lower);
174
175 for item in iter {
176 result.push(Ustr::from(item.as_ref()));
177 }
178
179 result
180}
181
182#[cfg(test)]
186#[allow(clippy::unnecessary_to_owned)]
187mod tests {
188 use std::collections::{HashMap, HashSet};
189
190 use ahash::{AHashMap, AHashSet};
191 use indexmap::{IndexMap, IndexSet};
192 use rstest::*;
193 use ustr::Ustr;
194
195 use super::*;
196
197 #[rstest]
198 fn test_hashset_setlike() {
199 let mut set: HashSet<String> = HashSet::new();
200 set.insert("test".to_string());
201 set.insert("value".to_string());
202
203 assert!(set.contains(&"test".to_string()));
204 assert!(!set.contains(&"missing".to_string()));
205 assert!(!set.is_empty());
206
207 let empty_set: HashSet<String> = HashSet::new();
208 assert!(empty_set.is_empty());
209 }
210
211 #[rstest]
212 fn test_indexset_setlike() {
213 let mut set: IndexSet<String> = IndexSet::new();
214 set.insert("test".to_string());
215 set.insert("value".to_string());
216
217 assert!(set.contains(&"test".to_string()));
218 assert!(!set.contains(&"missing".to_string()));
219 assert!(!set.is_empty());
220
221 let empty_set: IndexSet<String> = IndexSet::new();
222 assert!(empty_set.is_empty());
223 }
224
225 #[rstest]
226 fn test_into_ustr_vec_from_strings() {
227 let items = vec!["foo".to_string(), "bar".to_string()];
228 let ustrs = super::into_ustr_vec(items);
229
230 assert_eq!(ustrs.len(), 2);
231 assert_eq!(ustrs[0], Ustr::from("foo"));
232 assert_eq!(ustrs[1], Ustr::from("bar"));
233 }
234
235 #[rstest]
236 fn test_into_ustr_vec_from_str_slices() {
237 let items = ["alpha", "beta", "gamma"];
238 let ustrs = super::into_ustr_vec(items);
239
240 assert_eq!(ustrs.len(), 3);
241 assert_eq!(ustrs[2], Ustr::from("gamma"));
242 }
243
244 #[rstest]
245 fn test_ahashset_setlike() {
246 let mut set: AHashSet<String> = AHashSet::new();
247 set.insert("test".to_string());
248 set.insert("value".to_string());
249
250 assert!(set.contains(&"test".to_string()));
251 assert!(!set.contains(&"missing".to_string()));
252 assert!(!set.is_empty());
253
254 let empty_set: AHashSet<String> = AHashSet::new();
255 assert!(empty_set.is_empty());
256 }
257
258 #[rstest]
259 fn test_hashmap_maplike() {
260 let mut map: HashMap<String, i32> = HashMap::new();
261 map.insert("key1".to_string(), 42);
262 map.insert("key2".to_string(), 100);
263
264 assert!(map.contains_key(&"key1".to_string()));
265 assert!(!map.contains_key(&"missing".to_string()));
266 assert!(!map.is_empty());
267
268 let empty_map: HashMap<String, i32> = HashMap::new();
269 assert!(empty_map.is_empty());
270 }
271
272 #[rstest]
273 fn test_indexmap_maplike() {
274 let mut map: IndexMap<String, i32> = IndexMap::new();
275 map.insert("key1".to_string(), 42);
276 map.insert("key2".to_string(), 100);
277
278 assert!(map.contains_key(&"key1".to_string()));
279 assert!(!map.contains_key(&"missing".to_string()));
280 assert!(!map.is_empty());
281
282 let empty_map: IndexMap<String, i32> = IndexMap::new();
283 assert!(empty_map.is_empty());
284 }
285
286 #[rstest]
287 fn test_ahashmap_maplike() {
288 let mut map: AHashMap<String, i32> = AHashMap::new();
289 map.insert("key1".to_string(), 42);
290 map.insert("key2".to_string(), 100);
291
292 assert!(map.contains_key(&"key1".to_string()));
293 assert!(!map.contains_key(&"missing".to_string()));
294 assert!(!map.is_empty());
295
296 let empty_map: AHashMap<String, i32> = AHashMap::new();
297 assert!(empty_map.is_empty());
298 }
299
300 #[rstest]
301 fn test_trait_object_setlike() {
302 let mut hashset: HashSet<String> = HashSet::new();
303 hashset.insert("test".to_string());
304
305 let mut indexset: IndexSet<String> = IndexSet::new();
306 indexset.insert("test".to_string());
307
308 let sets: Vec<&dyn SetLike<Item = String>> = vec![&hashset, &indexset];
309
310 for set in sets {
311 assert!(set.contains(&"test".to_string()));
312 assert!(!set.is_empty());
313 }
314 }
315
316 #[rstest]
317 fn test_trait_object_maplike() {
318 let mut hashmap: HashMap<String, i32> = HashMap::new();
319 hashmap.insert("key".to_string(), 42);
320
321 let mut indexmap: IndexMap<String, i32> = IndexMap::new();
322 indexmap.insert("key".to_string(), 42);
323
324 let maps: Vec<&dyn MapLike<Key = String, Value = i32>> = vec![&hashmap, &indexmap];
325
326 for map in maps {
327 assert!(map.contains_key(&"key".to_string()));
328 assert!(!map.is_empty());
329 }
330 }
331}