xand-utils 1.0.0

A junk drawer of shared Rust utilities.
Documentation
use std::{
    sync::mpsc::Sender,
    thread::JoinHandle,
    time::{Duration, Instant},
};

/// Use this macro to execute a block of code (which must return a bool) repeatedly until the
/// provided timeout is hit. If the code blocks indefinitely, the timeout will not work.
// TODO: Move - possibly publish as OSS crate? Seems useful. Nice to not have to pass a closure.
#[macro_export]
macro_rules! timeout {
    ( $timeout:expr, $interval:expr, $f:block ) => {
        let (sender, receiver) = std::sync::mpsc::channel();
        timeout::send_to_channel_after_timeout($timeout, sender);
        loop {
            let passed = $f;
            if passed {
                break;
            }
            match receiver.try_recv() {
                Ok(true) => {
                    panic!("Assertion timed out!");
                }
                _ => {
                    std::thread::sleep($interval);
                }
            }
        }
    };
    ( $timeout:expr, $f:block ) => {
        timeout!($timeout, Duration::from_millis(10), $f)
    };
}

pub fn send_to_channel_after_timeout(d: Duration, sender: Sender<bool>) -> JoinHandle<()> {
    let start = Instant::now();
    std::thread::spawn(move || loop {
        if start + d < Instant::now() {
            let _ = sender.send(true);
            break;
        }
        std::thread::sleep(Duration::from_millis(10));
    })
}