1use left_right::{Absorb, ReadHandleFactory, WriteHandle};
10use std::collections::HashMap;
11use std::hash::Hash;
12use std::sync::Mutex;
13
14enum MapOp<K, V> {
15 Insert(K, V),
16 Clear,
17}
18
19impl<K: Eq + Hash + Clone, V: Clone> Absorb<MapOp<K, V>> for HashMap<K, V> {
20 fn absorb_first(&mut self, operation: &mut MapOp<K, V>, _other: &Self) {
21 match operation {
22 MapOp::Insert(k, v) => {
23 self.insert(k.clone(), v.clone());
24 }
25 MapOp::Clear => self.clear(),
26 }
27 }
28
29 fn sync_with(&mut self, first: &Self) {
30 self.clone_from(first);
31 }
32}
33
34pub struct LrMap<K: Eq + Hash + Clone, V: Clone> {
41 reader_factory: ReadHandleFactory<HashMap<K, V>>,
42 writer: Mutex<WriteHandle<HashMap<K, V>, MapOp<K, V>>>,
43}
44
45impl<K, V> LrMap<K, V>
46where
47 K: Eq + Hash + Clone + Send + Sync,
48 V: Clone + Send + Sync,
49{
50 pub fn new() -> Self {
51 let (writer, reader) = left_right::new_from_empty(HashMap::new());
52 let factory = reader.factory();
53 Self {
54 reader_factory: factory,
55 writer: Mutex::new(writer),
56 }
57 }
58
59 pub fn get<Q>(&self, key: &Q) -> Option<V>
61 where
62 K: std::borrow::Borrow<Q>,
63 Q: Hash + Eq + ?Sized,
64 {
65 let reader = self.reader_factory.handle();
66 reader.enter().and_then(|map| map.get(key).cloned())
67 }
68
69 pub fn insert(&self, key: K, value: V) {
70 if let Ok(mut w) = self.writer.lock() {
71 w.append(MapOp::Insert(key, value));
72 w.publish();
73 }
74 }
75
76 pub fn clear(&self) {
77 if let Ok(mut w) = self.writer.lock() {
78 w.append(MapOp::Clear);
79 w.publish();
80 }
81 }
82
83 pub fn len(&self) -> usize {
84 let reader = self.reader_factory.handle();
85 reader.enter().map(|m| m.len()).unwrap_or(0)
86 }
87
88 pub fn is_empty(&self) -> bool {
89 self.len() == 0
90 }
91}
92
93impl<K, V> Default for LrMap<K, V>
94where
95 K: Eq + Hash + Clone + Send + Sync,
96 V: Clone + Send + Sync,
97{
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use std::sync::Arc;
107
108 #[test]
109 fn insert_and_get() {
110 let map: LrMap<String, i32> = LrMap::new();
111 map.insert("a".into(), 1);
112 assert_eq!(map.get("a"), Some(1));
113 assert_eq!(map.get("b"), None);
114 }
115
116 #[test]
117 fn overwrite_key() {
118 let map: LrMap<String, i32> = LrMap::new();
119 map.insert("a".into(), 1);
120 map.insert("a".into(), 2);
121 assert_eq!(map.get("a"), Some(2));
122 }
123
124 #[test]
125 fn clear_removes_all() {
126 let map: LrMap<String, i32> = LrMap::new();
127 map.insert("a".into(), 1);
128 map.insert("b".into(), 2);
129 map.clear();
130 assert!(map.is_empty());
131 }
132
133 #[test]
134 fn concurrent_reads() {
135 let map: Arc<LrMap<String, i32>> = Arc::new(LrMap::new());
136 map.insert("key".into(), 42);
137
138 let handles: Vec<_> = (0..4)
139 .map(|_| {
140 let m = Arc::clone(&map);
141 std::thread::spawn(move || {
142 for _ in 0..100 {
143 assert_eq!(m.get("key"), Some(42));
144 }
145 })
146 })
147 .collect();
148
149 for h in handles {
150 h.join().expect("reader thread panicked");
151 }
152 }
153}