1use std::{borrow::Borrow, collections::HashMap, hash::Hash};
2
3pub trait HashmapExt<K, V> {
5 fn update<Q, F>(&mut self, k: &Q, f: F) -> Option<V>
11 where
12 Q: ?Sized,
13 K: Borrow<Q> + PartialEq + Eq + Hash,
14 Q: Hash + Eq,
15 V: Clone,
16 F: FnMut(&mut V);
17
18 fn update_or_insert<F>(&mut self, k: K, f: F, def: V) -> Option<V>
24 where
25 K: PartialEq + Eq + Hash,
26 V: Clone,
27 F: FnMut(&mut V);
28}
29
30impl<K, V> HashmapExt<K, V> for HashMap<K, V> {
31 fn update<Q, F>(&mut self, k: &Q, mut f: F) -> Option<V>
32 where
33 Q: ?Sized,
34 K: Borrow<Q> + PartialEq + Eq + Hash,
35 Q: Hash + Eq,
36 V: Clone,
37 F: FnMut(&mut V),
38 {
39 if let Some(totals) = self.get_mut(k) {
40 f(totals);
41 Some(totals.clone())
42 } else {
43 None
44 }
45 }
46
47 fn update_or_insert<F>(&mut self, k: K, f: F, def: V) -> Option<V>
48 where
49 K: PartialEq + Eq + Hash,
50 V: Clone,
51 F: FnMut(&mut V),
52 {
53 self.update(&k, f).or_else(|| {
54 self.insert(k, def.clone());
55 Some(def)
56 })
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn not_exist_update() {
66 let mut map: HashMap<usize, u8> = HashMap::new();
67 let res = map.update(&1usize, |u| *u += 1);
68 assert!(res.is_none())
69 }
70
71 #[test]
72 fn exist_update() {
73 let mut map: HashMap<usize, u8> = HashMap::new();
74 let res = map.insert(1usize, 10);
75 assert!(res.is_none());
76
77 let res = map.update(&1usize, |u| *u += 1);
78 assert!(res.is_some());
79 assert_eq!(Some(11), res);
80 }
81
82 #[test]
83 fn not_exist_continuation() {
84 let mut map: HashMap<usize, u8> = HashMap::new();
85
86 let res = map
87 .update(&1usize, |u| *u += 1)
88 .or_else(|| map.insert(1usize, 1).or(Some(1)));
89 assert_eq!(res, Some(1));
90 }
91
92 #[test]
93 fn exist_continuation() {
94 let mut map: HashMap<usize, u8> = HashMap::new();
95 let res = map.insert(1usize, 10);
96 assert!(res.is_none());
97
98 let res = map
99 .update(&1usize, |u| *u += 1)
100 .or_else(|| map.insert(1usize, 1).or(Some(1)));
101 assert_eq!(res, Some(11));
102 }
103
104 #[test]
105 fn not_exist_update_or_insert() {
106 let mut map: HashMap<usize, u8> = HashMap::new();
107 let res = map.update_or_insert(1usize, |u| *u += 1, 1);
108 assert_eq!(res, Some(1));
109 }
110
111 #[test]
112 fn exist_update_or_insert() {
113 let mut map: HashMap<usize, u8> = HashMap::new();
114 let res = map.insert(1usize, 10);
115 assert!(res.is_none());
116
117 let res = map.update_or_insert(1usize, |u| *u += 1, 1);
118 assert_eq!(res, Some(11));
119 }
120}