use std::sync::{Arc, Mutex};
pub use std::thread::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ThreadStatus {
Running,
Finished,
Panicked,
}
impl ThreadStatus {
pub fn is_running(self) -> bool {
self == ThreadStatus::Running
}
pub fn finished(self) -> bool {
self == ThreadStatus::Finished
}
pub fn panicked(self) -> bool {
self == ThreadStatus::Panicked
}
}
pub struct SmartHandle<T> {
handle: JoinHandle<Result<T>>,
status: Arc<Mutex<ThreadStatus>>,
}
impl<T> SmartHandle<T> {
pub fn join(self) -> Result<T> {
self.handle.join().and_then(|r| r)
}
pub fn status(&self) -> ThreadStatus {
self.status
.lock()
.map(|guard| ThreadStatus::clone(&*guard))
.unwrap_or(ThreadStatus::Panicked)
}
pub fn thread(&self) -> &Thread {
self.handle.thread()
}
pub fn into_inner(self) -> JoinHandle<Result<T>> {
self.handle
}
}
pub fn spawn_smart<F, T>(f: F) -> SmartHandle<T>
where
F: FnOnce() -> T + Send + std::panic::UnwindSafe + 'static,
T: Send + 'static,
{
let status = Arc::new(Mutex::new(ThreadStatus::Running));
let status_clone = Arc::clone(&status);
SmartHandle {
status,
handle: spawn(move || {
let res = match std::panic::catch_unwind(f) {
Ok(res) => res,
Err(e) => {
if let Ok(mut status) = status_clone.lock() {
*status = ThreadStatus::Panicked;
}
return Err(e);
}
};
if let Ok(mut status) = status_clone.lock() {
*status = ThreadStatus::Finished;
}
Ok(res)
}),
}
}