use futures::{future, Future, FutureExt as _};
#[cfg(not(web))]
pub trait MaybeSend: Send {}
#[cfg(not(web))]
impl<T: Send> MaybeSend for T {}
#[cfg(web)]
pub trait MaybeSend {}
#[cfg(web)]
impl<T> MaybeSend for T {}
pub async fn run_detached<F, R>(future: F) -> R
where
F: Future<Output = R> + MaybeSend + 'static,
R: MaybeSend + 'static,
{
#[cfg(not(web))]
{
tokio::task::spawn(future)
.await
.unwrap_or_else(|e| std::panic::resume_unwind(e.into_panic()))
}
#[cfg(web)]
{
let (tx, rx) = futures::channel::oneshot::channel();
wasm_bindgen_futures::spawn_local(async move {
if tx.send(future.await).is_err() {
tracing::debug!("run_detached: receiver dropped before result was delivered");
}
});
rx.await
.expect("spawned task dropped without sending its result")
}
}
pub struct Task<R> {
abort_handle: future::AbortHandle,
output: future::RemoteHandle<Result<R, future::Aborted>>,
}
impl<R: 'static> Task<R> {
fn spawn_<F: Future<Output = R>, T>(
future: F,
spawn: impl FnOnce(future::Remote<future::Abortable<F>>) -> T,
) -> Self {
let (abortable_future, abort_handle) = future::abortable(future);
let (task, output) = abortable_future.remote_handle();
let _ = spawn(task);
Self {
abort_handle,
output,
}
}
#[cfg(not(web))]
pub fn spawn<F: Future<Output = R> + Send + 'static>(future: F) -> Self
where
R: Send,
{
Self::spawn_(future, tokio::task::spawn)
}
#[cfg(web)]
pub fn spawn<F: Future<Output = R> + 'static>(future: F) -> Self {
Self::spawn_(future, wasm_bindgen_futures::spawn_local)
}
pub fn ready(value: R) -> Self {
Self::spawn_(async { value }, |fut| {
fut.now_or_never().expect("the future is ready")
})
}
pub async fn cancel(self) {
self.abort_handle.abort();
let _ = self.output.await;
}
pub fn forget(self) {
self.output.forget();
}
}
impl<R: 'static> std::future::IntoFuture for Task<R> {
type Output = R;
type IntoFuture = future::Map<
future::RemoteHandle<Result<R, future::Aborted>>,
fn(Result<R, future::Aborted>) -> R,
>;
fn into_future(self) -> Self::IntoFuture {
self.output
.map(|result| result.expect("we have the only AbortHandle"))
}
}