xand_utils/
timeout.rs

1use std::{
2    sync::mpsc::Sender,
3    thread::JoinHandle,
4    time::{Duration, Instant},
5};
6
7/// Use this macro to execute a block of code (which must return a bool) repeatedly until the
8/// provided timeout is hit. If the code blocks indefinitely, the timeout will not work.
9// TODO: Move - possibly publish as OSS crate? Seems useful. Nice to not have to pass a closure.
10#[macro_export]
11macro_rules! timeout {
12    ( $timeout:expr, $interval:expr, $f:block ) => {
13        let (sender, receiver) = std::sync::mpsc::channel();
14        timeout::send_to_channel_after_timeout($timeout, sender);
15        loop {
16            let passed = $f;
17            if passed {
18                break;
19            }
20            match receiver.try_recv() {
21                Ok(true) => {
22                    panic!("Assertion timed out!");
23                }
24                _ => {
25                    std::thread::sleep($interval);
26                }
27            }
28        }
29    };
30    ( $timeout:expr, $f:block ) => {
31        timeout!($timeout, Duration::from_millis(10), $f)
32    };
33}
34
35pub fn send_to_channel_after_timeout(d: Duration, sender: Sender<bool>) -> JoinHandle<()> {
36    let start = Instant::now();
37    std::thread::spawn(move || loop {
38        if start + d < Instant::now() {
39            let _ = sender.send(true);
40            break;
41        }
42        std::thread::sleep(Duration::from_millis(10));
43    })
44}