use std::any::Any;
use std::panic;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::thread;
use std::thread::JoinHandle;
use std::time::Duration;
pub fn spawn_with_timeout<F, T>(f: F) -> JoinHandleWithTimeout<T>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
let (tx, rx) = channel();
let handle = thread::spawn(move || {
let val = panic::catch_unwind(panic::AssertUnwindSafe(f));
tx.send(()).unwrap();
val
});
JoinHandleWithTimeout { handle, rx }
}
pub struct JoinHandleWithTimeout<T> {
handle: JoinHandle<thread::Result<T>>,
rx: Receiver<()>,
}
#[derive(Debug)]
pub enum JoinError {
Panic(Box<dyn Any>),
Timeout,
}
impl<T> JoinHandleWithTimeout<T> {
pub fn try_join(self, timeout: Duration) -> Result<T, JoinError> {
if self.rx.recv_timeout(timeout).is_ok() {
self.handle.join().unwrap().map_err(|e| JoinError::Panic(e))
} else {
Err(JoinError::Timeout)
}
}
}