#![doc = include_str!("../README.md")]
use std::{time, time::Duration, ops::Deref, sync::{Arc, Condvar, Mutex, MutexGuard}, mem};
use std::ops::DerefMut;
#[cfg(windows)]
pub mod windows;
#[derive(Debug, PartialEq)]
pub enum WaitObjectError {
OsError(isize, String),
SynchronizationBroken,
Timeout
}
pub type Result<T> = std::result::Result<T, WaitObjectError>;
#[derive(Clone)]
pub struct WaitEvent<T>(Arc<(Mutex<T>, Condvar)>);
#[derive(Clone)]
pub struct ManualResetEvent(WaitEvent<bool>);
#[derive(Clone)]
pub struct AutoResetEvent(WaitEvent<bool>);
pub trait SignalWaitable {
fn wait_until_set(&self) -> Result<()>;
fn wait(&self, timeout: Duration) -> Result<()>;
fn set(&mut self) -> Result<()>;
fn reset(&mut self) -> Result<()>;
}
impl<T> WaitEvent<T> {
#[inline]
pub fn new_init(initial_state: T) -> Self {
Self(Arc::new((Mutex::new(initial_state), Condvar::new())))
}
pub fn value(&self) -> Result<MutexGuard<T>> {
self.0.0.lock().map_err(|e| e.into())
}
pub fn wait(&self, timeout: Option<Duration>, checker: impl FnMut(&T) -> bool) -> Result<MutexGuard<T>> {
match timeout {
Some(_) => self.wait_with_waiter(timeout, checker),
None => self.wait_with_waiter(timeout, checker)
}
}
pub fn wait_reset(&self, timeout: Option<Duration>, reset: impl FnMut() -> T, checker: impl FnMut(&T) -> bool) -> Result<T> {
match timeout {
Some(_) => self.wait_and_reset_with_waiter(timeout, checker, reset),
None => self.wait_and_reset_with_waiter(timeout, checker, reset)
}
}
pub fn wait_with_waiter(&self, timeout: Option<Duration>, mut checker: impl FnMut(&T) -> bool) -> Result<MutexGuard<T>> {
let (lock, cond) = self.0.deref();
let mut state = lock.lock()?;
let waiter = Self::create_waiter(timeout);
let mut continue_wait = waiter();
let mut pass = checker(&*state);
while continue_wait && !pass {
state = match timeout {
Some(t) => {
let (g, _) = cond.wait_timeout(state, t)?;
g
},
None => cond.wait(state)?
};
continue_wait = waiter();
pass = checker(&*state);
}
if pass { Ok(state) }
else { Err(WaitObjectError::Timeout) }
}
pub fn wait_and_reset_with_waiter(&self, timeout: Option<Duration>, checker: impl FnMut(&T) -> bool, mut reset: impl FnMut() -> T) -> Result<T> {
let state = self.wait_with_waiter(timeout, checker);
state.map(|mut g| mem::replace(g.deref_mut(), reset()))
}
pub fn set_state(&mut self, new_state: T) -> Result<()> {
let (lock, cond) = self.0.deref();
let mut state = lock.lock()?;
*state = new_state;
cond.notify_all();
Ok(())
}
pub fn set_state_func<F>(&mut self, setter: F) -> Result<()>
where F: FnOnce(&T) -> T
{
let (lock, cond) = self.0.deref();
let mut state = lock.lock()?;
*state = setter(&*state);
cond.notify_all();
Ok(())
}
fn create_waiter(timeout: Option<Duration>) -> impl Fn() -> bool {
let start = time::Instant::now();
move || {
match timeout {
Some(t) => (time::Instant::now() - start) < t,
None => true
}
}
}
}
impl ManualResetEvent {
#[inline]
pub fn new() -> Self { Self::new_init(false) }
#[inline]
pub fn new_init(initial_state: bool) -> Self {
Self(WaitEvent::new_init(initial_state))
}
}
impl SignalWaitable for ManualResetEvent {
#[inline] fn wait_until_set(&self) -> Result<()> { self.0.wait(None, |v| *v).map(|_| ()) }
#[inline] fn wait(&self, timeout: Duration) -> Result<()> { self.0.wait(Some(timeout), |v| *v).map(|_| ()) }
#[inline] fn set(&mut self) -> Result<()> {
self.0.set_state(true)
}
#[inline] fn reset(&mut self) -> Result<()> {
self.0.set_state(false)
}
}
impl AutoResetEvent {
#[inline] pub fn new() -> Self { Self::new_init(false) }
#[inline] pub fn new_init(initial_state: bool) -> Self { Self(WaitEvent::new_init(initial_state)) }
}
impl SignalWaitable for AutoResetEvent {
#[inline] fn wait_until_set(&self) -> Result<()> { self.0.wait_reset(None, || false, |v| *v).map(|_| ()) }
#[inline] fn wait(&self, timeout: Duration) -> Result<()> { self.0.wait_reset(Some(timeout), || false, |v| *v).map(|_| ()) }
#[inline] fn set(&mut self) -> Result<()> {
self.0.set_state(true)
}
#[inline] fn reset(&mut self) -> Result<()> {
self.0.set_state(false)
}
}
impl<T> From<std::sync::PoisonError<T>> for WaitObjectError {
fn from(_value: std::sync::PoisonError<T>) -> Self {
Self::SynchronizationBroken
}
}
impl From<WaitEvent<bool>> for ManualResetEvent {
fn from(value: WaitEvent<bool>) -> Self {
Self(value)
}
}
impl From<ManualResetEvent> for WaitEvent<bool> {
fn from(value: ManualResetEvent) -> Self {
value.0
}
}
impl From<WaitEvent<bool>> for AutoResetEvent {
fn from(value: WaitEvent<bool>) -> Self {
Self(value)
}
}
impl From<AutoResetEvent> for WaitEvent<bool> {
fn from(value: AutoResetEvent) -> Self {
value.0
}
}