use std::error::Error;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use crate::events::event::{try_consume_one, AutoUnregister};
use crate::Event;
use super::waiter::{Signaler, Waiter};
type WaitOne = Waiter<bool>;
impl Signaler for WaitOne {
fn fire(&self, pos: usize) -> Result<(), Box<dyn Error>> {
let lock = self.lock();
let mut data = match lock {
Ok(data) => data,
Err(error) => {
return Err(format!("Failed to fire event: {}", error).into());
}
};
*data = pos == 0;
self.condvar.notify_all();
Ok(())
}
fn clear(&self, _: usize) -> Result<(), Box<dyn Error>> {
Ok(())
}
}
pub fn wait_one(event: &dyn Event, dur: Duration) -> Result<bool, Box<dyn Error>> {
if event.handle().is_set() && try_consume_one(event)? {
return Ok(true);
}
let signaler = Arc::new(WaitOne::new(false));
let registered = AutoUnregister::register_signaler(Arc::<WaitOne>::clone(&signaler), 0, event)?;
let start = SystemTime::now();
let mut dur_remaining = dur;
let result = loop {
let data = signaler.lock()?;
let lock_result = signaler
.condvar
.wait_timeout_while(data, dur_remaining, |fired| !*fired);
let (mut fired, timeout) = match lock_result {
Ok(result) => result,
Err(error) => break Err(format!("Wait failed: {}", error).into()),
};
if timeout.timed_out() {
break Ok(false);
}
if event.handle().can_consume() && try_consume_one(event)? {
break Ok(true);
}
*fired = false;
let result = start.elapsed();
match result {
Ok(elapsed) => dur_remaining = dur - elapsed,
Err(_) => {
break Ok(false);
}
}
};
drop(registered);
result
}