use std::{any::Any, path::PathBuf};
use ahash::HashMap;
use poll_promise::Promise;
const FILE_SAVER_PROMISE: &str = "file_saver";
#[derive(Default)]
pub struct BackgroundTasks {
promises: HashMap<String, Promise<Box<dyn Any + Send>>>,
}
impl BackgroundTasks {
#[cfg(not(target_arch = "wasm32"))]
pub fn spawn_threaded_promise<F, T>(
&mut self,
name: impl Into<String>,
f: F,
) -> anyhow::Result<()>
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
let name = name.into();
if self.promises.contains_key(&name) {
anyhow::bail!("there's already a promise {name:?} running!");
}
let f = move || Box::new(f()) as Box<dyn Any + Send>; let promise = Promise::spawn_thread(&name, f);
self.promises.insert(name, promise);
Ok(())
}
#[cfg(not(target_arch = "wasm32"))]
pub fn spawn_file_saver<F>(&mut self, f: F) -> anyhow::Result<()>
where
F: FnOnce() -> anyhow::Result<PathBuf> + Send + 'static,
{
self.spawn_threaded_promise(FILE_SAVER_PROMISE, f)
}
pub fn poll_promise<T: Any>(&mut self, name: impl AsRef<str>) -> Option<T> {
self.promises
.remove(name.as_ref())
.and_then(|promise| match promise.try_take() {
Ok(any) => Some(*any.downcast::<T>().unwrap()),
Err(promise) => {
self.promises.insert(name.as_ref().to_owned(), promise);
None
}
})
}
pub fn poll_file_saver_promise(&mut self) -> Option<anyhow::Result<PathBuf>> {
self.poll_promise(FILE_SAVER_PROMISE)
}
pub fn is_file_save_in_progress(&self) -> bool {
self.promises.contains_key(FILE_SAVER_PROMISE)
}
}