win-events 0.0.2

A poor attempt to implement WaitForMultipleObjects and the ManualReset, AutoReset and Pulse types
Documentation
use std::collections::VecDeque;
use std::error::Error;
use std::sync::Arc;
use std::time::{Duration, SystemTime};

use crate::events::event::{try_consume_one, AutoUnregister};
use crate::waiters::waiter::{Signaler, Waiter};
use crate::Event;

type WaitFirst = Waiter<i32>;

impl Signaler for WaitFirst {
    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 as i32;
        self.condvar.notify_all();
        Ok(())
    }

    fn clear(&self, _: usize) -> Result<(), Box<dyn Error>> {
        Ok(())
    }
}

/// Waits for the first event to fire and returns the position of the event given
///
/// # Examples
///
/// This example spawns a thread that will set the third event created after a short delay.
///
/// The main thread will wait on all three events and return a position of two for the third event
/// of the provided events
///
///```
/// use std::thread::{sleep, spawn};
/// use std::time::Duration;
/// use win_events::{ManualResetEvent, wait_first};
///
/// let evt0 = ManualResetEvent::new(false);
/// let evt1 = ManualResetEvent::new(false);
/// let evt2 = ManualResetEvent::new(false);
/// let evt_inner = evt2.clone();
///
/// let worker = spawn(move || {
///    sleep(Duration::from_millis(10));
///    evt_inner.set()
/// });
///
/// let wait_result = wait_first(
///    vec![&evt0, &evt1, &evt2],
///    Duration::from_millis(100),
/// ).unwrap();
///
/// assert_eq!(2, wait_result);
/// worker.join().unwrap()
///```
pub fn wait_first(events: Vec<&dyn Event>, dur: Duration) -> Result<i32, Box<dyn Error>> {
    let signaler = Arc::new(WaitFirst::new(-1));
    let mut registered_waits: VecDeque<AutoUnregister> = VecDeque::new();
    for (pos, event) in events.iter().enumerate() {
        if event.handle().is_set() && try_consume_one(*event)? {
            return Ok(pos as i32);
        }

        registered_waits.push_back(AutoUnregister::register_signaler(
            Arc::<WaitFirst>::clone(&signaler),
            pos,
            *event,
        )?);
    }

    // wait on the event to be fired
    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 == -1);

        let (mut fired, timeout) = match lock_result {
            Ok(result) => result,
            Err(error) => break Err(format!("Wait failed: {}", error).into()),
        };

        // Check if it timed out
        if timeout.timed_out() {
            break Ok(-1);
        }

        // try to consume the event that triggered the wake
        let event = events[*fired as usize];
        if event.handle().can_consume() && try_consume_one(event)? {
            break Ok(*fired);
        }

        // recheck and try to consume the other events
        for (pos, event) in events.iter().enumerate() {
            if *fired != pos as i32 && event.handle().can_consume() && try_consume_one(*event)? {
                return Ok(pos as i32);
            }
        }

        // reset fired event value
        *fired = -1;

        // Calculate the remaining time
        let result = start.elapsed();
        match result {
            Ok(remaining) => dur_remaining = remaining,
            // The system time can change and cause this to return early... I'm sure it's fine
            Err(_) => break Ok(-1),
        }
    };

    drop(registered_waits);
    result
}