64 lines
1.8 KiB
Rust
64 lines
1.8 KiB
Rust
use std::{
|
|
ops::Deref,
|
|
sync::Mutex,
|
|
thread::{self, JoinHandle},
|
|
};
|
|
|
|
enum InternalPromiseState<T: Send + Clone> {
|
|
Loading(Option<JoinHandle<Result<T, anyhow::Error>>>),
|
|
Result(Result<T, anyhow::Error>),
|
|
}
|
|
|
|
impl<T: Send + Clone> InternalPromiseState<T> {
|
|
fn loading(&mut self) -> Option<JoinHandle<anyhow::Result<T>>> {
|
|
match self {
|
|
Self::Loading(handle) => handle.take(),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Promise<T: Send + Clone> {
|
|
internal: Mutex<InternalPromiseState<T>>,
|
|
}
|
|
|
|
impl<T: Send + Clone> Promise<T> {
|
|
pub fn new<F>(f: F) -> Promise<T>
|
|
where
|
|
F: Fn() -> anyhow::Result<T> + Send + 'static,
|
|
T: 'static,
|
|
{
|
|
let thread = thread::spawn(f);
|
|
|
|
Promise {
|
|
internal: Mutex::new(InternalPromiseState::Loading(Some(thread))),
|
|
}
|
|
}
|
|
|
|
pub fn get(&self) -> T {
|
|
let mut internal = self.internal.lock().expect("promise lock is poisoned");
|
|
|
|
if let Some(handle) = internal.loading() {
|
|
let result = handle.join();
|
|
|
|
match result {
|
|
Ok(result) => match result {
|
|
Ok(t) => *internal = InternalPromiseState::Result(Ok(t)),
|
|
Err(err) => *internal = InternalPromiseState::Result(Err(err)),
|
|
},
|
|
Err(err) => {
|
|
println!("Promise Thread Join Error: {:?}", err);
|
|
|
|
*internal = InternalPromiseState::Result(Err(anyhow::Error::msg(
|
|
"Failed joining thread",
|
|
)))
|
|
}
|
|
}
|
|
}
|
|
|
|
match internal.deref() {
|
|
InternalPromiseState::Result(t) => t.as_ref().expect("result error").clone(),
|
|
InternalPromiseState::Loading(_) => unreachable!(),
|
|
}
|
|
}
|
|
}
|