1use std::sync::Arc;
29use std::sync::Mutex;
30use std::sync::Weak;
31
32#[cfg(test)]
33use mockall::predicate::*;
34#[cfg(test)]
35use mockall::*;
36
37type WeakObserver<T> = Weak<Mutex<Box<dyn Observer<T> + Send>>>;
38
39#[cfg_attr(test, automock)]
43pub trait Observer<T> {
44 fn notify(&mut self, message: T);
46}
47
48pub trait Observable<T> {
53 fn attach(&mut self, observer: WeakObserver<T>);
57
58 fn detach(&mut self, observer: WeakObserver<T>);
62}
63
64#[derive(Clone)]
66pub struct ObserverList<T> {
67 observers: Arc<Mutex<Vec<WeakObserver<T>>>>,
69}
70
71impl<T> ObserverList<T> {
72 pub fn new() -> Self {
74 ObserverList {
75 observers: Arc::new(Mutex::new(vec![])),
76 }
77 }
78
79 pub fn count(&self) -> usize {
81 self.observers
82 .lock()
83 .unwrap()
84 .iter()
85 .filter(|r| r.upgrade().is_some())
86 .count()
87 }
88}
89
90impl<T> Observable<T> for ObserverList<T> {
91 fn attach(&mut self, observer: Weak<Mutex<Box<dyn Observer<T> + Send>>>) {
95 let mut observers = self.observers.lock().unwrap();
96 if !observers.iter().any(|o| o.ptr_eq(&observer)) {
97 observers.push(observer);
98 }
99 }
100
101 fn detach(&mut self, observer: Weak<Mutex<Box<dyn Observer<T> + Send>>>) {
105 self.observers
106 .lock()
107 .unwrap()
108 .retain(|o| o.upgrade().is_some() && !o.ptr_eq(&observer));
109 }
110}
111
112impl<T: Clone> ObserverList<T> {
113 pub fn notify(&self, message: T) {
117 self.observers.lock().unwrap().iter().for_each(|o| {
118 if let Some(mutex) = o.upgrade() {
119 if let Ok(mut observer) = mutex.lock() {
120 observer.notify(message.clone());
121 }
122 }
123 })
124 }
125}
126
127impl<T> Default for ObserverList<T> {
128 fn default() -> Self {
129 ObserverList::new()
130 }
131}
132
133#[cfg(test)]
134mod test {
135 use super::*;
136 use std::sync::Arc;
137
138 #[test]
139 fn observer_list_attach_detach() {
140 let mut observer_list = ObserverList::new();
141
142 let observer1 = MockObserver::new();
143
144 let observer1_ref = Arc::new(Mutex::new(
145 Box::new(observer1) as Box<dyn Observer<u64> + Send>
146 ));
147
148 observer_list.attach(Arc::downgrade(&observer1_ref));
149
150 assert_eq!(
151 1,
152 observer_list.count(),
153 "The observable does not have the correct amount of observers"
154 );
155
156 observer_list.detach(Arc::downgrade(&observer1_ref));
157
158 assert_eq!(
159 0,
160 observer_list.count(),
161 "The observable does not have the correct amount of observers"
162 );
163 }
164
165 #[test]
166 fn observer_list_notify() {
167 let mut observer_list = ObserverList::new();
168
169 let mut observer1 = MockObserver::new();
170 observer1
171 .expect_notify()
172 .with(predicate::eq(10u64))
173 .times(1)
174 .returning(|_| ());
175
176 let observer1_ref = Arc::new(Mutex::new(
177 Box::new(observer1) as Box<dyn Observer<u64> + Send>
178 ));
179
180 observer_list.attach(Arc::downgrade(&observer1_ref));
181 observer_list.notify(10);
182 }
183
184 #[test]
185 fn observable_multi_observer() {
186 let mut observer_list = ObserverList::new();
187
188 let mut observer1 = MockObserver::new();
189 observer1
190 .expect_notify()
191 .with(predicate::eq(10u64))
192 .times(1)
193 .returning(|_| ());
194 observer1
195 .expect_notify()
196 .with(predicate::eq(20u64))
197 .times(1)
198 .returning(|_| ());
199
200 let mut observer2 = MockObserver::new();
201 observer2
202 .expect_notify()
203 .with(predicate::eq(20u64))
204 .times(1)
205 .returning(|_| ());
206
207 let observer1_ref = Arc::new(Mutex::new(
208 Box::new(observer1) as Box<dyn Observer<u64> + Send>
209 ));
210 let observer2_ref = Arc::new(Mutex::new(
211 Box::new(observer2) as Box<dyn Observer<u64> + Send>
212 ));
213
214 observer_list.attach(Arc::downgrade(&observer1_ref));
215 observer_list.notify(10);
216
217 observer_list.attach(Arc::downgrade(&observer2_ref));
218 observer_list.notify(20);
219 }
220
221 #[test]
222 fn observer_list_test_drop_inactive() {
223 let mut observer_list = ObserverList::new();
224
225 let observer1 = MockObserver::new();
226
227 let observer1_ref = Arc::new(Mutex::new(
228 Box::new(observer1) as Box<dyn Observer<u64> + Send>
229 ));
230
231 observer_list.attach(Arc::downgrade(&observer1_ref));
232
233 assert_eq!(
234 1,
235 observer_list.observers.lock().unwrap().len(),
236 "The observable does not have the correct amount of observers"
237 );
238
239 observer_list.detach(Weak::new());
240
241 assert_eq!(
242 1,
243 observer_list.observers.lock().unwrap().len(),
244 "The observable does not have the correct amount of observers"
245 );
246
247 drop(observer1_ref);
248 observer_list.detach(Weak::new());
249
250 assert_eq!(
251 0,
252 observer_list.observers.lock().unwrap().len(),
253 "The observable does not have the correct amount of observers"
254 );
255 }
256
257 #[test]
258 fn observer_list_test_clone() {
259 let mut observer_list = ObserverList::new();
260
261 let mut observer1 = MockObserver::new();
262 observer1
263 .expect_notify()
264 .with(predicate::eq(10u64))
265 .times(1)
266 .returning(|_| ());
267
268 let observer1_ref = Arc::new(Mutex::new(
269 Box::new(observer1) as Box<dyn Observer<u64> + Send>
270 ));
271
272 observer_list.attach(Arc::downgrade(&observer1_ref));
273
274 assert_eq!(
275 1,
276 observer_list.count(),
277 "The observable does not have the correct amount of observers"
278 );
279
280 let observer_list2 = observer_list.clone();
281
282 assert_eq!(
283 1,
284 observer_list2.count(),
285 "The observable does not have the correct amount of observers"
286 );
287
288 observer_list2.notify(10);
289 }
290
291 #[test]
292 fn observer_list_test_clone_pre_attach() {
293 let mut observer_list = ObserverList::new();
294
295 let mut observer1 = MockObserver::new();
296 observer1
297 .expect_notify()
298 .with(predicate::eq(10u64))
299 .times(1)
300 .returning(|_| ());
301
302 let observer1_ref = Arc::new(Mutex::new(
303 Box::new(observer1) as Box<dyn Observer<u64> + Send>
304 ));
305
306 let observer_list2 = observer_list.clone();
307
308 observer_list.attach(Arc::downgrade(&observer1_ref));
309 drop(observer_list);
310
311 assert_eq!(
312 1,
313 observer_list2.count(),
314 "The observable does not have the correct amount of observers"
315 );
316
317 observer_list2.notify(10);
318 }
319}