use std::collections::VecDeque;
use std::error::Error;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use crate::events::event::{try_consume_all, AutoUnregister};
use crate::waiters::waiter::{Signaler, Waiter};
use crate::Event;
struct Positions {
vec: Vec<bool>,
remaining: usize,
}
type WaitAll = Waiter<Positions>;
impl Signaler for WaitAll {
fn fire(&self, pos: usize) -> Result<(), Box<dyn Error>> {
let completed = {
let lock = self.lock();
let mut data = match lock {
Ok(data) => data,
Err(error) => {
return Err(format!("Failed to set event: {}", error).into());
}
};
if data.vec[pos] == true {
return Ok(());
}
data.vec[pos] = true;
data.remaining -= 1;
data.remaining == 0
};
if completed {
self.condvar.notify_all();
}
Ok(())
}
fn clear(&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 set event: {}", error).into()),
};
if data.vec[pos] == false {
return Ok(());
}
data.vec[pos] = false;
data.remaining += 1;
Ok(())
}
}
pub fn wait_all(events: Vec<&dyn Event>, dur: Duration) -> Result<bool, Box<dyn Error>> {
let events = {
let mut sorted_events = events;
sorted_events.sort_by_key(|e| Arc::as_ptr(e.handle()));
sorted_events
};
let signaler = Arc::new(WaitAll::new(Positions {
remaining: events.len(),
vec: vec![false; events.len()],
}));
let mut registered_locks = VecDeque::new();
for (pos, event) in events.iter().enumerate() {
registered_locks.push_back(AutoUnregister::register_signaler(
Arc::<WaitAll>::clone(&signaler),
pos,
*event,
)?);
}
let start = SystemTime::now();
let mut dur_remaining = dur;
let result = loop {
let lock = signaler.lock()?;
let lock_result = signaler
.condvar
.wait_timeout_while(lock, dur_remaining, |pos| pos.remaining > 0);
let (mut positions, timeout) = match lock_result {
Ok(result) => result,
Err(error) => break Err(format!("Wait failed: {}", error).into()),
};
if timeout.timed_out() {
break Ok(false);
}
if try_consume_all(&events)? {
break Ok(true);
}
positions.remaining = 0;
for (pos, event) in events.iter().enumerate() {
let set = event.handle().is_set();
if !set {
positions.remaining += 1
}
positions.vec[pos] = set
}
match start.elapsed() {
Ok(elapsed) => {
if elapsed > dur_remaining {
break Ok(false);
}
dur_remaining = dur - elapsed;
}
Err(_) => break Ok(false),
}
};
drop(registered_locks);
result
}