use std::collections::LinkedList;
use std::error::Error;
use std::sync::{Arc, Condvar, Mutex, MutexGuard};
#[derive(Clone)]
pub(crate) struct WaitInfo {
pub(crate) pos: usize,
pub(crate) signaler: Arc<dyn Signaler>,
}
pub(crate) trait Signaler: Send + Sync {
fn fire(&self, pos: usize) -> Result<(), Box<dyn Error>>;
fn clear(&self, pos: usize) -> Result<(), Box<dyn Error>>;
}
pub(crate) struct Waiter<Data> {
d: Mutex<Data>,
pub(crate) condvar: Condvar,
}
impl<Data> Waiter<Data> {
pub(crate) fn new(d: Data) -> Waiter<Data> {
Waiter {
d: Mutex::new(d),
condvar: Condvar::new(),
}
}
pub(crate) fn lock(&self) -> Result<MutexGuard<Data>, Box<dyn Error>> {
let lock = self.d.lock();
match lock {
Ok(data) => Ok(data),
Err(error) => {
return Err(format!("Failed to grab wait mutex: {}", error).into());
}
}
}
}
pub(crate) struct WaitList {
waiters: Mutex<LinkedList<WaitInfo>>,
}
impl WaitList {
pub(crate) fn new() -> WaitList {
WaitList {
waiters: Mutex::new(LinkedList::new()),
}
}
pub(crate) fn fire(&self) {
let result = self.waiters.lock();
let waiters = match result {
Ok(waiters) => waiters,
Err(_) => return,
};
for waiter in waiters.iter() {
let result = waiter.signaler.fire(waiter.pos);
match result {
Ok(_) => {}
Err(_) => {}
}
}
}
pub(crate) fn clear(&self) {
let result = self.waiters.lock();
let waiters = match result {
Ok(waiters) => waiters,
Err(_) => return,
};
for waiter in waiters.iter() {
let result = waiter.signaler.clear(waiter.pos);
match result {
Ok(_) => {}
Err(_) => {}
}
}
}
pub(crate) fn register_signaler(
&self,
pos: usize,
signaler: Arc<dyn Signaler>,
) -> Result<(), Box<dyn Error>> {
let result = self.waiters.lock();
match result {
Ok(mut waiters) => {
waiters.push_back(WaitInfo { pos, signaler });
Ok(())
}
Err(error) => Err(format!("Could not grab registered waiters lock {}", error).into()),
}
}
pub(crate) fn remove_signaler(
&self,
signaler: &Arc<dyn Signaler>,
) -> Result<(), Box<dyn Error>> {
let result = self.waiters.lock();
match result {
Ok(mut waiters) => {
*waiters = {
let list = waiters.clone();
let iter = list.into_iter();
let filtered = iter.filter(|info| Arc::ptr_eq(&info.signaler, signaler));
filtered.collect()
};
Ok(())
}
Err(error) => Err(format!("Could not grab registered waiters lock {}", error).into()),
}
}
}