ferroui_base/utilities/
ref_counting_small_dictionary.rs1use super::small_dictionary::{InlineDictionary, InlineDictionaryEnumerator};
2use std::hash::Hash;
3
4pub struct RefCountingSmallDictionary<TKey> {
6 counts: InlineDictionary<TKey, i32>,
7}
8
9impl<TKey: Clone + Eq + Hash> Default for RefCountingSmallDictionary<TKey> {
10 fn default() -> Self {
11 Self { counts: InlineDictionary::new() }
12 }
13}
14
15impl<TKey: Clone + Eq + Hash> RefCountingSmallDictionary<TKey> {
16 pub fn add(&mut self, key: TKey) -> bool {
18 let (cnt, exists) = self.counts.get_value_ref_or_add_default(key);
19 *cnt += 1;
20 !exists
21 }
22
23 pub fn remove(&mut self, key: &TKey) -> bool {
27 let remaining = match self.counts.get_value_ref_or_null_ref(key) {
28 Some(cnt) => {
29 *cnt -= 1;
30 *cnt
31 }
32 None => panic!("Object reference not set to an instance of an object."),
33 };
34 if remaining == 0 {
35 self.counts.remove(key);
36 return true;
37 }
38
39 false
40 }
41
42 pub fn get_enumerator(&self) -> InlineDictionaryEnumerator<'_, TKey, i32> {
43 self.counts.get_enumerator()
44 }
45}
46
47impl<'a, TKey: Clone + Eq + Hash> IntoIterator for &'a RefCountingSmallDictionary<TKey> {
48 type Item = (&'a TKey, &'a i32);
49 type IntoIter = InlineDictionaryEnumerator<'a, TKey, i32>;
50
51 fn into_iter(self) -> Self::IntoIter {
52 self.get_enumerator()
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
60
61 #[test]
62 fn counts_references() {
63 let mut target = RefCountingSmallDictionary::<&'static str>::default();
64
65 assert!(target.add("a"));
66 assert!(!target.add("a"));
67 assert!(target.add("b"));
68
69 let counts: Vec<(&'static str, i32)> = target.get_enumerator().map(|(key, count)| (*key, *count)).collect();
70 assert_eq!(vec![("a", 2), ("b", 1)], counts);
71
72 assert!(!target.remove(&"a"));
73 assert!(target.remove(&"a"));
74 assert!(target.remove(&"b"));
75 assert_eq!(0, target.get_enumerator().count());
76 }
77
78 #[test]
79 #[should_panic(expected = "Object reference not set to an instance of an object.")]
80 fn remove_of_a_key_without_reference_throws() {
81 let mut target = RefCountingSmallDictionary::<&'static str>::default();
82 target.remove(&"a");
83 }
84}