implicit_clone/
map.rs

1use indexmap::map::Iter as MapIter;
2use indexmap::map::Keys as MapKeys;
3use indexmap::map::Values as MapValues;
4use indexmap::IndexMap as Map;
5use std::borrow::Borrow;
6use std::fmt;
7use std::hash::Hash;
8
9use crate::ImplicitClone;
10
11use super::IString;
12use super::Rc;
13
14/// An immutable hash map type inspired by [Immutable.js](https://immutable-js.com/).
15///
16/// This type is cheap to clone and thus implements [`ImplicitClone`]. It can be created based on a
17/// `&'static [(K, V)]`, or based on a reference counted
18/// [`IndexMap`](https://crates.io/crates/indexmap).
19///
20/// This type has the least stable API at the moment and is subject to change a lot before the 1.0
21/// release.
22#[cfg_attr(docsrs, doc(cfg(feature = "map")))]
23#[derive(PartialEq, Eq)]
24pub enum IMap<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> {
25    /// A (small) static map.
26    Static(&'static [(K, V)]),
27    /// An reference counted map.
28    Rc(Rc<Map<K, V>>),
29}
30
31// TODO add insta tests
32impl<
33        K: fmt::Debug + Eq + Hash + ImplicitClone + 'static,
34        V: fmt::Debug + PartialEq + ImplicitClone + 'static,
35    > fmt::Debug for IMap<K, V>
36{
37    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38        match self {
39            Self::Static(a) => a.fmt(f),
40            Self::Rc(a) => a.fmt(f),
41        }
42    }
43}
44
45impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> Clone
46    for IMap<K, V>
47{
48    fn clone(&self) -> Self {
49        match self {
50            Self::Static(a) => Self::Static(a),
51            Self::Rc(a) => Self::Rc(a.clone()),
52        }
53    }
54}
55
56impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> Default
57    for IMap<K, V>
58{
59    fn default() -> Self {
60        Self::Static(&[])
61    }
62}
63
64impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
65    FromIterator<(K, V)> for IMap<K, V>
66{
67    fn from_iter<I: IntoIterator<Item = (K, V)>>(it: I) -> Self {
68        let vec = it.into_iter().collect::<Map<K, V>>();
69        Self::Rc(Rc::from(vec))
70    }
71}
72
73impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> ImplicitClone
74    for IMap<K, V>
75{
76}
77
78impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
79    From<&'static [(K, V)]> for IMap<K, V>
80{
81    fn from(a: &'static [(K, V)]) -> IMap<K, V> {
82        IMap::Static(a)
83    }
84}
85
86impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> From<Map<K, V>>
87    for IMap<K, V>
88{
89    fn from(a: Map<K, V>) -> IMap<K, V> {
90        IMap::Rc(Rc::new(a))
91    }
92}
93
94impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
95    From<Rc<Map<K, V>>> for IMap<K, V>
96{
97    fn from(a: Rc<Map<K, V>>) -> IMap<K, V> {
98        IMap::Rc(a)
99    }
100}
101
102impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
103    From<&IMap<K, V>> for IMap<K, V>
104{
105    fn from(a: &IMap<K, V>) -> IMap<K, V> {
106        a.clone()
107    }
108}
109
110impl<K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> IMap<K, V> {
111    /// Return an iterator over the key-value pairs of the map, in their order.
112    #[inline]
113    pub fn iter(&self) -> IMapIter<K, V> {
114        match self {
115            Self::Static(a) => IMapIter::Slice(a.iter()),
116            Self::Rc(a) => IMapIter::Map(a.iter()),
117        }
118    }
119
120    /// Return an iterator over the keys of the map, in their order.
121    #[inline]
122    pub fn keys(&self) -> IMapKeys<K, V> {
123        match self {
124            Self::Static(a) => IMapKeys::Slice(a.iter()),
125            Self::Rc(a) => IMapKeys::Map(a.keys()),
126        }
127    }
128
129    /// Return an iterator over the values of the map, in their order.
130    #[inline]
131    pub fn values(&self) -> IMapValues<K, V> {
132        match self {
133            Self::Static(a) => IMapValues::Slice(a.iter()),
134            Self::Rc(a) => IMapValues::Map(a.values()),
135        }
136    }
137
138    /// Return the number of key-value pairs in the map.
139    ///
140    /// Computes in **O(1)** time.
141    #[inline]
142    pub fn len(&self) -> usize {
143        match self {
144            Self::Static(a) => a.len(),
145            Self::Rc(a) => a.len(),
146        }
147    }
148
149    /// Returns true if the map contains no elements.
150    ///
151    /// Computes in **O(1)** time.
152    #[inline]
153    pub fn is_empty(&self) -> bool {
154        match self {
155            Self::Static(a) => a.is_empty(),
156            Self::Rc(a) => a.is_empty(),
157        }
158    }
159
160    /// Return a clone to the value stored for `key`, if it is present,
161    /// else `None`.
162    ///
163    /// Computes in **O(1)** time (average).
164    #[inline]
165    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<V>
166    where
167        K: Borrow<Q>,
168        Q: Hash + Eq,
169    {
170        match self {
171            Self::Static(a) => a
172                .iter()
173                .find_map(|(k, v)| (k.borrow() == key).then(|| v))
174                .cloned(),
175            Self::Rc(a) => a.get(key).cloned(),
176        }
177    }
178
179    /// Return clones to the key-value pair stored for `key`,
180    /// if it is present, else `None`.
181    ///
182    /// Computes in **O(1)** time (average).
183    #[inline]
184    pub fn get_key_value<Q: ?Sized>(&self, key: &Q) -> Option<(K, V)>
185    where
186        K: Borrow<Q>,
187        Q: Hash + Eq,
188    {
189        match self {
190            Self::Static(a) => a.iter().find(|(k, _)| k.borrow() == key).cloned(),
191            Self::Rc(a) => a.get_key_value(key).map(|(k, v)| (k.clone(), v.clone())),
192        }
193    }
194
195    /// Return item index, key and value
196    #[inline]
197    pub fn get_full<Q: ?Sized>(&self, key: &Q) -> Option<(usize, K, V)>
198    where
199        K: Borrow<Q>,
200        Q: Hash + Eq,
201    {
202        match self {
203            Self::Static(a) => a
204                .iter()
205                .enumerate()
206                .find_map(|(i, (k, v))| (k.borrow() == key).then(|| (i, k.clone(), v.clone()))),
207            Self::Rc(a) => a.get_full(key).map(|(i, k, v)| (i, k.clone(), v.clone())),
208        }
209    }
210
211    /// Get a key-value pair by index.
212    ///
213    /// Valid indices are *0 <= index < self.len()*
214    ///
215    /// Computes in **O(1)** time.
216    #[inline]
217    pub fn get_index(&self, index: usize) -> Option<(K, V)> {
218        match self {
219            Self::Static(a) => a.get(index).cloned(),
220            Self::Rc(a) => a.get_index(index).map(|(k, v)| (k.clone(), v.clone())),
221        }
222    }
223
224    /// Return item index, if it exists in the map.
225    ///
226    /// Computes in **O(1)** time (average).
227    #[inline]
228    pub fn get_index_of<Q: ?Sized>(&self, key: &Q) -> Option<usize>
229    where
230        K: Borrow<Q>,
231        Q: Hash + Eq,
232    {
233        match self {
234            Self::Static(a) => a
235                .iter()
236                .enumerate()
237                .find_map(|(i, (k, _))| (k.borrow() == key).then(|| i)),
238            Self::Rc(a) => a.get_index_of(key),
239        }
240    }
241
242    /// Return `true` if an equivalent to `key` exists in the map.
243    ///
244    /// Computes in **O(1)** time (average).
245    #[inline]
246    pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
247    where
248        K: Borrow<Q>,
249        Q: Hash + Eq,
250    {
251        match self {
252            Self::Static(a) => a.iter().any(|(k, _)| k.borrow() == key),
253            Self::Rc(a) => a.contains_key(key),
254        }
255    }
256
257    /// Get the last key-value pair.
258    ///
259    /// Computes in **O(1)** time.
260    #[inline]
261    pub fn last(&self) -> Option<(K, V)> {
262        match self {
263            Self::Static(a) => a.last().cloned(),
264            Self::Rc(a) => a.last().map(|(k, v)| (k.clone(), v.clone())),
265        }
266    }
267}
268
269impl<V: PartialEq + ImplicitClone + 'static> IMap<IString, V> {
270    #[doc(hidden)]
271    #[inline]
272    pub fn get_static_str(&self, key: &'static str) -> Option<V> {
273        let key = IString::from(key);
274        match self {
275            Self::Static(a) => a.iter().find_map(|(k, v)| (*k == key).then(|| v)).cloned(),
276            Self::Rc(a) => a.get(&key).cloned(),
277        }
278    }
279}
280
281impl<V: PartialEq + ImplicitClone + 'static> IMap<&'static str, V> {
282    #[doc(hidden)]
283    #[inline]
284    pub fn get_static_str(&self, key: &'static str) -> Option<V> {
285        match self {
286            Self::Static(a) => a.iter().find_map(|(k, v)| (*k == key).then(|| v)).cloned(),
287            Self::Rc(a) => a.get(key).cloned(),
288        }
289    }
290}
291
292#[allow(missing_docs, missing_debug_implementations)]
293pub enum IMapIter<'a, K, V> {
294    Slice(std::slice::Iter<'a, (K, V)>),
295    Map(MapIter<'a, K, V>),
296}
297
298impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> Iterator
299    for IMapIter<'a, K, V>
300{
301    type Item = (K, V);
302
303    fn next(&mut self) -> Option<Self::Item> {
304        match self {
305            Self::Slice(it) => it.next().map(|(k, v)| (k.clone(), v.clone())),
306            Self::Map(it) => it.next().map(|(k, v)| (k.clone(), v.clone())),
307        }
308    }
309}
310
311#[allow(missing_docs, missing_debug_implementations)]
312pub enum IMapKeys<'a, K, V> {
313    Slice(std::slice::Iter<'a, (K, V)>),
314    Map(MapKeys<'a, K, V>),
315}
316
317impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> Iterator
318    for IMapKeys<'a, K, V>
319{
320    type Item = K;
321
322    fn next(&mut self) -> Option<Self::Item> {
323        match self {
324            Self::Slice(it) => it.next().map(|(k, _)| k.clone()),
325            Self::Map(it) => it.next().cloned(),
326        }
327    }
328}
329
330#[allow(missing_docs, missing_debug_implementations)]
331pub enum IMapValues<'a, K, V> {
332    Slice(std::slice::Iter<'a, (K, V)>),
333    Map(MapValues<'a, K, V>),
334}
335
336impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> Iterator
337    for IMapValues<'a, K, V>
338{
339    type Item = V;
340
341    fn next(&mut self) -> Option<Self::Item> {
342        match self {
343            Self::Slice(it) => it.next().map(|(_, v)| v.clone()),
344            Self::Map(it) => it.next().cloned(),
345        }
346    }
347}
348
349#[cfg(feature = "serde")]
350impl<K, V> serde::Serialize for IMap<K, V>
351where
352    K: Eq + Hash + ImplicitClone + 'static + serde::Serialize,
353    V: PartialEq + ImplicitClone + 'static + serde::Serialize,
354{
355    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
356        use serde::ser::SerializeMap;
357        let mut seq = serializer.serialize_map(Some(self.len()))?;
358        match self {
359            Self::Static(a) => {
360                for (k, v) in a.iter() {
361                    seq.serialize_entry(k, v)?;
362                }
363            }
364            Self::Rc(a) => {
365                for (k, v) in a.iter() {
366                    seq.serialize_entry(k, v)?;
367                }
368            }
369        }
370        seq.end()
371    }
372}
373
374#[cfg(feature = "serde")]
375impl<'de, K, V> serde::Deserialize<'de> for IMap<K, V>
376where
377    K: Eq + Hash + ImplicitClone + 'static + serde::Deserialize<'de>,
378    V: PartialEq + ImplicitClone + 'static + serde::Deserialize<'de>,
379{
380    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
381        <Map<K, V> as serde::Deserialize>::deserialize(deserializer).map(IMap::<K, V>::from)
382    }
383}
384
385#[cfg(test)]
386mod test_map {
387    use super::*;
388
389    #[test]
390    fn map_in_map() {
391        let map_1 = [
392            (IString::from("foo1"), 1),
393            (IString::from("bar1"), 2),
394            (IString::from("baz1"), 3),
395        ]
396        .into_iter()
397        .collect::<IMap<IString, u32>>();
398        let map_2 = [
399            (IString::from("foo2"), 4),
400            (IString::from("bar2"), 5),
401            (IString::from("baz2"), 6),
402        ]
403        .into_iter()
404        .collect::<IMap<IString, u32>>();
405        let map_of_map = [("map_1", map_1), ("map_2", map_2)]
406            .into_iter()
407            .collect::<IMap<&'static str, IMap<IString, u32>>>();
408        let flattened_vec = map_of_map
409            .iter()
410            .flat_map(|(_key, map)| map.iter().collect::<Vec<(_, _)>>())
411            .collect::<Vec<(_, _)>>();
412        // TODO allow PartialEq IString with &str
413        assert_eq!(
414            flattened_vec,
415            [
416                (IString::from("foo1"), 1),
417                (IString::from("bar1"), 2),
418                (IString::from("baz1"), 3),
419                (IString::from("foo2"), 4),
420                (IString::from("bar2"), 5),
421                (IString::from("baz2"), 6),
422            ]
423        );
424    }
425
426    #[test]
427    fn static_map() {
428        const _MAP: IMap<&str, u32> = IMap::Static(&[("foo", 1)]);
429    }
430
431    #[test]
432    fn floats_in_map() {
433        const _MAP_F32: IMap<u32, f32> = IMap::Static(&[]);
434        const _MAP_F64: IMap<u32, f64> = IMap::Static(&[]);
435    }
436
437    #[test]
438    fn from() {
439        let x: IMap<u32, u32> = IMap::Static(&[]);
440        let _out = IMap::from(&x);
441    }
442}