use std::{sync::{Condvar, LockResult, Mutex, MutexGuard, PoisonError, TryLockError, TryLockResult, WaitTimeoutResult}, time::Duration};
use delegate::delegate;
static FAILED_TO_UNLOCK_MUTEX_MESSAGE: &str = "Failed to unlock Mutex.";
pub struct Notifier<T = ()>
{
mtx: Mutex<T>,
cndvr: Condvar
}
impl<T> Notifier<T>
{
pub fn new(value: T) -> Self
{
Self
{
mtx: Mutex::new(value),
cndvr: Condvar::new()
}
}
pub fn wait<'a>(&'a self) -> Result<MutexGuard<T>, PoisonError<MutexGuard<T>>> {
let mtx_lk_res = self.mtx.lock();
match mtx_lk_res
{
Ok(res) =>
{
self.cndvr.wait(res)
},
Err(_) =>
{
mtx_lk_res
}
}
}
pub fn wait_fn<'a, F>(&'a self, mut func: F) -> Option<Result<MutexGuard<T>, PoisonError<MutexGuard<T>>>>
where F: FnMut(&mut MutexGuard<T>) -> bool
{
let mtx_lk_res = self.mtx.lock();
match mtx_lk_res
{
Ok(mut res) =>
{
if func(&mut res)
{
Some(self.cndvr.wait(res))
}
else
{
None
}
},
Err(_) =>
{
Some(mtx_lk_res)
}
}
}
pub fn wait_timeout<'a>(&'a self, dur: Duration) -> Result<LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>, PoisonError<MutexGuard<'_, T>>> {
let mtx_lk_res = self.mtx.lock();
match mtx_lk_res
{
Ok(res) =>
{
Ok(self.cndvr.wait_timeout(res, dur))
}
Err(err) =>
{
Err(err)
}
}
}
pub fn wait_timeout_fn<'a, F>(&'a self, dur: Duration, mut func: F) -> Option<Result<LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>, PoisonError<MutexGuard<'_, T>>>> where F: FnMut(&mut MutexGuard<T>) -> bool
{
let mtx_lk_res = self.mtx.lock();
match mtx_lk_res
{
Ok(mut res) =>
{
if func(&mut res)
{
Some(Ok(self.cndvr.wait_timeout(res, dur)))
}
else
{
None
}
}
Err(err) =>
{
Some(Err(err))
}
}
}
pub fn try_wait<'a>(&'a self) -> Result<LockResult<MutexGuard<'a, T>>, TryLockError<MutexGuard<'_, T>>> {
let mtx_lk_res = self.mtx.try_lock();
match mtx_lk_res
{
Ok(res) =>
{
Ok(self.cndvr.wait(res))
},
Err(err) =>
{
Err(err)
}
}
}
pub fn try_wait_timeout<'a>(&'a self, dur: Duration) -> Result<LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>, TryLockError<MutexGuard<'_, T>>> {
let mtx_lk_res = self.mtx.try_lock();
match mtx_lk_res
{
Ok(res) =>
{
Ok(self.cndvr.wait_timeout(res, dur))
},
Err(err) =>
{
Err(err)
}
}
}
delegate! {
to self.cndvr {
pub fn notify_one(&self);
pub fn notify_all(&self);
}
}
delegate! {
to self.mtx {
pub fn lock(&self) -> Result<MutexGuard<'_, T>, PoisonError<MutexGuard<'_, T>>>;
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>>;
pub fn is_poisoned(&self);
pub fn clear_poison(&self);
}
}
pub fn try_set_notify_one(&self, value: T) -> Result<(), PoisonError<MutexGuard<'_, T>>> {
let mtx_lk_res = self.mtx.lock();
match mtx_lk_res
{
Ok(mut res) =>
{
*res = value;
},
Err(err) =>
{
return Err(err);
}
}
self.cndvr.notify_one();
Ok(())
}
pub fn try_set_notify_all(&self, value: T) -> Result<(), PoisonError<MutexGuard<'_, T>>> {
let mtx_lk_res = self.mtx.lock();
match mtx_lk_res
{
Ok(mut res) =>
{
*res = value;
},
Err(err) =>
{
return Err(err);
}
}
self.cndvr.notify_all();
Ok(())
}
pub fn try_lock_set_notify_one(&self, value: T) -> Result<(), (TryLockError<()>, T)>
{
let notify_one_res;
match self.mtx.try_lock()
{
Ok(mut res) =>
{
*res = value;
notify_one_res = Ok(());
}
Err(err) =>
{
match err
{
TryLockError::Poisoned(_) =>
{
return Err((TryLockError::Poisoned(PoisonError::new(())), value));
}
TryLockError::WouldBlock =>
{
return Err((TryLockError::WouldBlock, value));
}
}
}
}
self.cndvr.notify_one();
notify_one_res
}
pub fn try_lock_set_notify_all(&self, value: T) -> Result<(), (TryLockError<()>, T)> {
let notify_all_res;
match self.mtx.try_lock()
{
Ok(mut res) =>
{
*res = value;
notify_all_res = Ok(());
}
Err(err) =>
{
match err
{
TryLockError::Poisoned(_) =>
{
return Err((TryLockError::Poisoned(PoisonError::new(())), value));
}
TryLockError::WouldBlock =>
{
return Err((TryLockError::WouldBlock, value));
}
}
}
}
self.cndvr.notify_all();
notify_all_res
}
pub fn must_set_notify_one(&self, value: T)
{
{
let mut res = self.mtx.lock().expect(FAILED_TO_UNLOCK_MUTEX_MESSAGE);
*res = value;
}
self.cndvr.notify_one();
}
pub fn must_set_notify_all(&self, value: T)
{
{
let mut res = self.mtx.lock().expect(FAILED_TO_UNLOCK_MUTEX_MESSAGE);
*res = value;
}
self.cndvr.notify_all();
}
}
impl<T> Default for Notifier<T>
where T: Default
{
fn default() -> Self
{
Self
{
mtx: Mutex::new(T::default()),
cndvr: Condvar::default()
}
}
}