win_events/waiters/
wait_one.rs

1use std::error::Error;
2use std::sync::Arc;
3use std::time::{Duration, SystemTime};
4
5use crate::events::event::{try_consume_one, AutoUnregister};
6use crate::Event;
7
8use super::waiter::{Signaler, Waiter};
9
10type WaitOne = Waiter<bool>;
11
12impl Signaler for WaitOne {
13    fn fire(&self, pos: usize) -> Result<(), Box<dyn Error>> {
14        let lock = self.lock();
15        let mut data = match lock {
16            Ok(data) => data,
17            Err(error) => {
18                return Err(format!("Failed to fire event: {}", error).into());
19            }
20        };
21
22        *data = pos == 0;
23        self.condvar.notify_all();
24        Ok(())
25    }
26
27    fn clear(&self, _: usize) -> Result<(), Box<dyn Error>> {
28        Ok(())
29    }
30}
31
32/// Waits for a single event to be fired
33///
34/// # Examples
35///
36/// This example spawns a thread that will set the event of the created event after a short delay.
37///
38/// The main thread will wait on the event and return true if it's been set, otherwise it will
39/// timeout and return false
40///
41///```
42/// use std::thread::{sleep, spawn};
43/// use std::time::Duration;
44/// use win_events::{ManualResetEvent, wait_one};
45///
46/// let evt0 = ManualResetEvent::new(false);
47/// let evt_inner = evt0.clone();
48///
49/// let worker = spawn(move || {
50///    sleep(Duration::from_millis(10));
51///    evt_inner.set()
52/// });
53///
54/// let wait_result = wait_one(
55///    &evt0,
56///    Duration::from_millis(100),
57/// ).unwrap();
58///
59/// assert_eq!(true, wait_result);
60/// worker.join().unwrap()
61///```
62pub fn wait_one(event: &dyn Event, dur: Duration) -> Result<bool, Box<dyn Error>> {
63    // Check to see if the event is already fired, if it is no need to even wait
64    if event.handle().is_set() && try_consume_one(event)? {
65        return Ok(true);
66    }
67
68    let signaler = Arc::new(WaitOne::new(false));
69
70    // Register the signaler info with the registered handlers
71
72    let registered = AutoUnregister::register_signaler(Arc::<WaitOne>::clone(&signaler), 0, event)?;
73
74    // wait on the event to be fired
75    let start = SystemTime::now();
76    let mut dur_remaining = dur;
77    let result = loop {
78        let data = signaler.lock()?;
79        let lock_result = signaler
80            .condvar
81            .wait_timeout_while(data, dur_remaining, |fired| !*fired);
82
83        let (mut fired, timeout) = match lock_result {
84            Ok(result) => result,
85            Err(error) => break Err(format!("Wait failed: {}", error).into()),
86        };
87
88        // Check to see if the wait timed out
89        if timeout.timed_out() {
90            break Ok(false);
91        }
92
93        // consume the event
94        if event.handle().can_consume() && try_consume_one(event)? {
95            break Ok(true);
96        }
97
98        // reset fired event value
99        *fired = false;
100
101        // Calculate the remaining time
102        let result = start.elapsed();
103        match result {
104            Ok(elapsed) => dur_remaining = dur - elapsed,
105            // The system time can change and cause this to return early... I'm sure it's fine
106            Err(_) => {
107                break Ok(false);
108            }
109        }
110    };
111
112    // release this here
113    drop(registered);
114    result
115}