use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;
#[cfg(test)]
use mockall::predicate::*;
#[cfg(test)]
use mockall::*;
type WeakObserver<T> = Weak<Mutex<Box<dyn Observer<T> + Send>>>;
#[cfg_attr(test, automock)]
pub trait Observer<T> {
fn notify(&mut self, message: T);
}
pub trait Observable<T> {
fn attach(&mut self, observer: WeakObserver<T>);
fn detach(&mut self, observer: WeakObserver<T>);
}
#[derive(Clone)]
pub struct ObserverList<T> {
observers: Arc<Mutex<Vec<WeakObserver<T>>>>,
}
impl<T> ObserverList<T> {
pub fn new() -> Self {
ObserverList {
observers: Arc::new(Mutex::new(vec![])),
}
}
pub fn count(&self) -> usize {
self.observers
.lock()
.unwrap()
.iter()
.filter(|r| r.upgrade().is_some())
.count()
}
}
impl<T> Observable<T> for ObserverList<T> {
fn attach(&mut self, observer: Weak<Mutex<Box<dyn Observer<T> + Send>>>) {
let mut observers = self.observers.lock().unwrap();
if !observers.iter().any(|o| o.ptr_eq(&observer)) {
observers.push(observer);
}
}
fn detach(&mut self, observer: Weak<Mutex<Box<dyn Observer<T> + Send>>>) {
self.observers
.lock()
.unwrap()
.retain(|o| o.upgrade().is_some() && !o.ptr_eq(&observer));
}
}
impl<T: Clone> ObserverList<T> {
pub fn notify(&self, message: T) {
self.observers.lock().unwrap().iter().for_each(|o| {
if let Some(mutex) = o.upgrade() {
if let Ok(mut observer) = mutex.lock() {
observer.notify(message.clone());
}
}
})
}
}
impl<T> Default for ObserverList<T> {
fn default() -> Self {
ObserverList::new()
}
}
#[cfg(test)]
mod test {
use super::*;
use std::sync::Arc;
#[test]
fn observer_list_attach_detach() {
let mut observer_list = ObserverList::new();
let observer1 = MockObserver::new();
let observer1_ref = Arc::new(Mutex::new(
Box::new(observer1) as Box<dyn Observer<u64> + Send>
));
observer_list.attach(Arc::downgrade(&observer1_ref));
assert_eq!(
1,
observer_list.count(),
"The observable does not have the correct amount of observers"
);
observer_list.detach(Arc::downgrade(&observer1_ref));
assert_eq!(
0,
observer_list.count(),
"The observable does not have the correct amount of observers"
);
}
#[test]
fn observer_list_notify() {
let mut observer_list = ObserverList::new();
let mut observer1 = MockObserver::new();
observer1
.expect_notify()
.with(predicate::eq(10u64))
.times(1)
.returning(|_| ());
let observer1_ref = Arc::new(Mutex::new(
Box::new(observer1) as Box<dyn Observer<u64> + Send>
));
observer_list.attach(Arc::downgrade(&observer1_ref));
observer_list.notify(10);
}
#[test]
fn observable_multi_observer() {
let mut observer_list = ObserverList::new();
let mut observer1 = MockObserver::new();
observer1
.expect_notify()
.with(predicate::eq(10u64))
.times(1)
.returning(|_| ());
observer1
.expect_notify()
.with(predicate::eq(20u64))
.times(1)
.returning(|_| ());
let mut observer2 = MockObserver::new();
observer2
.expect_notify()
.with(predicate::eq(20u64))
.times(1)
.returning(|_| ());
let observer1_ref = Arc::new(Mutex::new(
Box::new(observer1) as Box<dyn Observer<u64> + Send>
));
let observer2_ref = Arc::new(Mutex::new(
Box::new(observer2) as Box<dyn Observer<u64> + Send>
));
observer_list.attach(Arc::downgrade(&observer1_ref));
observer_list.notify(10);
observer_list.attach(Arc::downgrade(&observer2_ref));
observer_list.notify(20);
}
#[test]
fn observer_list_test_drop_inactive() {
let mut observer_list = ObserverList::new();
let observer1 = MockObserver::new();
let observer1_ref = Arc::new(Mutex::new(
Box::new(observer1) as Box<dyn Observer<u64> + Send>
));
observer_list.attach(Arc::downgrade(&observer1_ref));
assert_eq!(
1,
observer_list.observers.lock().unwrap().len(),
"The observable does not have the correct amount of observers"
);
observer_list.detach(Weak::new());
assert_eq!(
1,
observer_list.observers.lock().unwrap().len(),
"The observable does not have the correct amount of observers"
);
drop(observer1_ref);
observer_list.detach(Weak::new());
assert_eq!(
0,
observer_list.observers.lock().unwrap().len(),
"The observable does not have the correct amount of observers"
);
}
#[test]
fn observer_list_test_clone() {
let mut observer_list = ObserverList::new();
let mut observer1 = MockObserver::new();
observer1
.expect_notify()
.with(predicate::eq(10u64))
.times(1)
.returning(|_| ());
let observer1_ref = Arc::new(Mutex::new(
Box::new(observer1) as Box<dyn Observer<u64> + Send>
));
observer_list.attach(Arc::downgrade(&observer1_ref));
assert_eq!(
1,
observer_list.count(),
"The observable does not have the correct amount of observers"
);
let observer_list2 = observer_list.clone();
assert_eq!(
1,
observer_list2.count(),
"The observable does not have the correct amount of observers"
);
observer_list2.notify(10);
}
#[test]
fn observer_list_test_clone_pre_attach() {
let mut observer_list = ObserverList::new();
let mut observer1 = MockObserver::new();
observer1
.expect_notify()
.with(predicate::eq(10u64))
.times(1)
.returning(|_| ());
let observer1_ref = Arc::new(Mutex::new(
Box::new(observer1) as Box<dyn Observer<u64> + Send>
));
let observer_list2 = observer_list.clone();
observer_list.attach(Arc::downgrade(&observer1_ref));
drop(observer_list);
assert_eq!(
1,
observer_list2.count(),
"The observable does not have the correct amount of observers"
);
observer_list2.notify(10);
}
}