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>(&self, key: &Q) -> Option<V>
166    where
167        K: Borrow<Q>,
168        Q: Hash + Eq + ?Sized,
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>(&self, key: &Q) -> Option<(K, V)>
185    where
186        K: Borrow<Q>,
187        Q: Hash + Eq + ?Sized,
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>(&self, key: &Q) -> Option<(usize, K, V)>
198    where
199        K: Borrow<Q>,
200        Q: Hash + Eq + ?Sized,
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>(&self, key: &Q) -> Option<usize>
229    where
230        K: Borrow<Q>,
231        Q: Hash + Eq + ?Sized,
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>(&self, key: &Q) -> bool
247    where
248        K: Borrow<Q>,
249        Q: Hash + Eq + ?Sized,
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 = (&'a K, &'a V);
302
303    fn next(&mut self) -> Option<Self::Item> {
304        match self {
305            Self::Slice(it) => it.next().map(|(k, v)| (k, v)),
306            Self::Map(it) => it.next(),
307        }
308    }
309}
310
311impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
312    DoubleEndedIterator for IMapIter<'a, K, V>
313{
314    fn next_back(&mut self) -> Option<Self::Item> {
315        match self {
316            Self::Slice(it) => it.next_back().map(|(k, v)| (k, v)),
317            Self::Map(it) => it.next_back(),
318        }
319    }
320}
321
322#[allow(missing_docs, missing_debug_implementations)]
323pub enum IMapKeys<'a, K, V> {
324    Slice(std::slice::Iter<'a, (K, V)>),
325    Map(MapKeys<'a, K, V>),
326}
327
328impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> Iterator
329    for IMapKeys<'a, K, V>
330{
331    type Item = &'a K;
332
333    fn next(&mut self) -> Option<Self::Item> {
334        match self {
335            Self::Slice(it) => it.next().map(|(k, _)| k),
336            Self::Map(it) => it.next(),
337        }
338    }
339}
340
341impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
342    DoubleEndedIterator for IMapKeys<'a, K, V>
343{
344    fn next_back(&mut self) -> Option<Self::Item> {
345        match self {
346            Self::Slice(it) => it.next_back().map(|(k, _)| k),
347            Self::Map(it) => it.next_back(),
348        }
349    }
350}
351
352#[allow(missing_docs, missing_debug_implementations)]
353pub enum IMapValues<'a, K, V> {
354    Slice(std::slice::Iter<'a, (K, V)>),
355    Map(MapValues<'a, K, V>),
356}
357
358impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static> Iterator
359    for IMapValues<'a, K, V>
360{
361    type Item = &'a V;
362
363    fn next(&mut self) -> Option<Self::Item> {
364        match self {
365            Self::Slice(it) => it.next().map(|(_, v)| v),
366            Self::Map(it) => it.next(),
367        }
368    }
369}
370
371impl<'a, K: Eq + Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>
372    DoubleEndedIterator for IMapValues<'a, K, V>
373{
374    fn next_back(&mut self) -> Option<Self::Item> {
375        match self {
376            Self::Slice(it) => it.next_back().map(|(_, v)| v),
377            Self::Map(it) => it.next_back(),
378        }
379    }
380}
381
382#[cfg(feature = "serde")]
383impl<K, V> serde::Serialize for IMap<K, V>
384where
385    K: Eq + Hash + ImplicitClone + 'static + serde::Serialize,
386    V: PartialEq + ImplicitClone + 'static + serde::Serialize,
387{
388    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
389        use serde::ser::SerializeMap;
390        let mut seq = serializer.serialize_map(Some(self.len()))?;
391        match self {
392            Self::Static(a) => {
393                for (k, v) in a.iter() {
394                    seq.serialize_entry(k, v)?;
395                }
396            }
397            Self::Rc(a) => {
398                for (k, v) in a.iter() {
399                    seq.serialize_entry(k, v)?;
400                }
401            }
402        }
403        seq.end()
404    }
405}
406
407#[cfg(feature = "serde")]
408impl<'de, K, V> serde::Deserialize<'de> for IMap<K, V>
409where
410    K: Eq + Hash + ImplicitClone + 'static + serde::Deserialize<'de>,
411    V: PartialEq + ImplicitClone + 'static + serde::Deserialize<'de>,
412{
413    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
414        <Map<K, V> as serde::Deserialize>::deserialize(deserializer).map(IMap::<K, V>::from)
415    }
416}
417
418#[cfg(test)]
419mod test_map {
420    use super::*;
421
422    #[test]
423    fn map_in_map() {
424        let map_1 = [
425            (IString::from("foo1"), 1),
426            (IString::from("bar1"), 2),
427            (IString::from("baz1"), 3),
428        ]
429        .into_iter()
430        .collect::<IMap<IString, u32>>();
431        let map_2 = [
432            (IString::from("foo2"), 4),
433            (IString::from("bar2"), 5),
434            (IString::from("baz2"), 6),
435        ]
436        .into_iter()
437        .collect::<IMap<IString, u32>>();
438        let map_of_map = [("map_1", map_1), ("map_2", map_2)]
439            .into_iter()
440            .collect::<IMap<&'static str, IMap<IString, u32>>>();
441        let flattened_vec = map_of_map
442            .iter()
443            .flat_map(|(_key, map)| map.iter().collect::<Vec<(_, _)>>())
444            .collect::<Vec<(_, _)>>();
445        // TODO allow PartialEq IString with &str
446        assert_eq!(
447            flattened_vec,
448            [
449                (&IString::from("foo1"), &1),
450                (&IString::from("bar1"), &2),
451                (&IString::from("baz1"), &3),
452                (&IString::from("foo2"), &4),
453                (&IString::from("bar2"), &5),
454                (&IString::from("baz2"), &6),
455            ]
456        );
457    }
458
459    #[test]
460    fn static_map() {
461        const _MAP: IMap<&str, u32> = IMap::Static(&[("foo", 1)]);
462    }
463
464    #[test]
465    fn floats_in_map() {
466        const _MAP_F32: IMap<u32, f32> = IMap::Static(&[]);
467        const _MAP_F64: IMap<u32, f64> = IMap::Static(&[]);
468    }
469
470    #[test]
471    fn from() {
472        let x: IMap<u32, u32> = IMap::Static(&[]);
473        let _out = IMap::from(&x);
474    }
475}