1use std::borrow::Borrow;
2use std::collections::HashMap;
3use std::hash::BuildHasher;
4use std::hash::Hash;
5use std::hash::RandomState;
6use std::ops::Index;
7
8type TFilterFn<K, V> = fn(&(&K, &V)) -> bool;
9
10#[derive(Clone, Debug)]
11pub struct ReadOnlyMap<
12 'a,
13 K,
14 V,
15 S = RandomState,
16> {
17 map: &'a HashMap<K, V, S>,
18 filter_fn: TFilterFn<K, V>,
19}
20
21impl<'a, K, V> ReadOnlyMap<'a, K, V, RandomState> {
22 #[inline]
23 pub fn new(
24 map: &'a HashMap<K, V>,
25 filter_fn: Option<TFilterFn<K, V>>,
26 ) -> ReadOnlyMap<'a, K, V, RandomState> {
27 Self {
28 map,
29 filter_fn: filter_fn.unwrap_or(|_| true),
30 }
31 }
32}
33
34impl<'a, K, V, S> ReadOnlyMap<'a, K, V, S> {
35 #[inline]
36 pub fn capacity(&self) -> usize {
37 self.map.capacity()
38 }
39
40 pub fn keys(&self) -> impl Iterator<Item = &K> {
41 self.iter().map(|(key, _val)| key)
42 }
43
44 pub fn values(&self) -> impl Iterator<Item = &V> {
45 self.iter().map(|(_key, val)| val)
46 }
47
48 pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
49 self.map.iter().filter(&self.filter_fn)
50 }
51
52 #[inline]
53 pub fn len(&self) -> usize {
54 self.map.len()
55 }
56
57 #[inline]
58 pub fn is_empty(&self) -> bool {
59 self.map.is_empty()
60 }
61
62 #[inline]
63 pub fn hasher(&self) -> &S {
64 self.map.hasher()
65 }
66}
67
68impl<
69 'a,
70 K: Eq + Hash,
71 V,
72 S: BuildHasher,
73> ReadOnlyMap<'a, K, V, S> {
74 #[inline]
75 pub fn get<Q>(&self, k: &Q) -> Option<&'a V>
76 where
77 K: Borrow<Q>,
78 Q: Hash + Eq + ?Sized,
79 {
80 let filter_fn = &self.filter_fn;
81 self.map.get_key_value(k).and_then(|(k, v)| {
82 if filter_fn(&(k, v)) {
83 Some(v)
84 } else {
85 None
86 }
87 })
88 }
89
90 #[inline]
91 pub fn get_key_value<Q>(&self, k: &Q) -> Option<(&'a K, &'a V)>
92 where
93 K: Borrow<Q>,
94 Q: Hash + Eq + ?Sized,
95 {
96 let filter_fn = &self.filter_fn;
97 self.map.get_key_value(k).filter(|(k, v)| filter_fn(&(k, v)))
98 }
99
100 #[inline]
101 pub fn contains_key<Q>(&self, k: &Q) -> bool
102 where
103 K: Borrow<Q>,
104 Q: Hash + Eq + ?Sized,
105 {
106 self.get(k).is_some()
107 }
108}
109
110impl<
111 'a,
112 K: Eq + Hash,
113 V: PartialEq,
114 S: BuildHasher,
115> PartialEq for ReadOnlyMap<'a, K, V, S> {
116 fn eq(&self, other: &ReadOnlyMap<'_, K, V, S>) -> bool {
117 self.iter().all(|(key, value)| other.get(key).is_some_and(|v| *value == *v))
118 }
119}
120
121impl<
122 'a,
123 K: Eq + Hash,
124 V: Eq,
125 S: BuildHasher,
126> Eq for ReadOnlyMap<'a, K, V, S> {}
127
128impl<
129 'a,
130 K,
131 V: Eq,
132 Q,
133 S: BuildHasher,
134> Index<&Q> for ReadOnlyMap<'a, K, V, S>
135where
136 K: Eq + Hash + Borrow<Q>,
137 Q: Hash + Eq + ?Sized,
138{
139 type Output = V;
140
141 #[inline]
142 fn index(&self, key: &Q) -> &'a V {
143 self.get(key).expect("no entry found for key")
144 }
145}