syntax_parser_generator/handles/collections/
handled_hash_map.rs

1use std::collections::HashMap;
2use std::hash::Hash;
3use std::ops::Index;
4
5use crate::handles::{Handle, Handled};
6
7/// A collection of [Handled] instances with automatically-generated handles, supporting efficient
8/// hash-based instance-to-handle lookup.
9///
10/// This data structure accumulates instances of some [Handled] type `T`, while automatically
11/// generating handles to each of the contained instances, based on their order of insertion to the
12/// vector. It supports efficient hash-based instance-to-handle lookup.
13///
14/// This usually serves for generating handles to instances of simple data types, not simple enough
15/// to be [AutomaticallyHandled](crate::handles::specials::AutomaticallyHandled).
16///
17/// # Example
18/// ```rust
19/// # use syntax_parser_generator::handles::collections::HandledHashMap;///
20/// # use syntax_parser_generator::handles::Handled;
21/// # #[derive(PartialEq, Eq, Hash)]
22/// struct Animal(String);
23/// impl Handled for Animal {
24///     type HandleCoreType = u8;
25/// }
26/// let mut animals = HandledHashMap::new();
27/// let dog_handle = animals.insert(Animal(String::from("dog")));
28/// let cat_handle = animals.insert(Animal(String::from("cat")));
29/// ```
30pub struct HandledHashMap<T>
31where
32    T: Handled + Eq + PartialEq + Hash,
33{
34    contents: HashMap<T, Handle<T>>,
35}
36
37impl<T> HandledHashMap<T>
38where
39    T: Handled + Eq + PartialEq + Hash,
40{
41    /// Create a new, empty, collection.
42    pub fn new() -> Self {
43        Self {
44            contents: HashMap::new(),
45        }
46    }
47
48    /// Check whether the collection contains a given item.
49    pub fn contains(&self, item: &T) -> bool {
50        self.contents.contains_key(item)
51    }
52
53    /// Insert a new item into the collection (if it is not already there).
54    pub fn insert(&mut self, item: T) {
55        if !self.contains(&item) {
56            let new_handle = self.contents.len().into();
57            self.contents.insert(item, new_handle);
58        }
59    }
60
61    /// Get the handle associated with one of the collection's items, or [None] if it isn't there.
62    pub fn get_handle(&self, item: &T) -> Option<&Handle<T>> {
63        self.contents.get(item)
64    }
65}
66
67impl<T> FromIterator<T> for HandledHashMap<T>
68where
69    T: Handled + Eq + PartialEq + Hash,
70{
71    fn from_iter<U: IntoIterator<Item=T>>(iter: U) -> Self {
72        let mut set = Self::new();
73        for item in iter {
74            set.insert(item);
75        }
76        set
77    }
78}
79
80impl<T> Index<T> for HandledHashMap<T>
81where
82    T: Handled + Eq + PartialEq + Hash,
83{
84    type Output = Handle<T>;
85
86    /// Get the handle associated with one of the collection's items.
87    fn index(&self, index: T) -> &Self::Output {
88        self.get_handle(&index)
89            .expect("No handles is associated with index item")
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    impl Handled for i32 {
98        type HandleCoreType = u8;
99    }
100
101    #[test]
102    fn test() {
103        let mut set = HandledHashMap::from_iter(1..10);
104        assert_eq!(set.contains(&1), true);
105        assert_eq!(set.contains(&0), false);
106        assert_eq!(set.contains(&5), true);
107
108        set.insert(1);
109        assert_eq!(set.contains(&1), true);
110
111        assert_eq!(set.contains(&12), false);
112        set.insert(12);
113        assert_eq!(set.contains(&12), true);
114
115        assert_eq!(set.contains(&15), false);
116        set.insert(15);
117        assert_eq!(set.contains(&15), true);
118
119        assert_ne!(set.get_handle(&12), None);
120        assert_eq!(set.get_handle(&5412), None);
121
122        assert_eq!(set.get_handle(&25), None);
123        set.insert(25);
124        let handle_of_25 = set.get_handle(&25).copied();
125        assert_ne!(set.get_handle(&25), None);
126        set.insert(25);
127        let handle_of_25_again = set.get_handle(&25).copied();
128        assert_eq!(handle_of_25, handle_of_25_again);
129    }
130}