1use futures::{future, Future, FutureExt as _};
9
10pub struct Task<R> {
17 abort_handle: future::AbortHandle,
18 output: future::RemoteHandle<Result<R, future::Aborted>>,
19}
20
21impl<R: 'static> Task<R> {
22 fn spawn_<F: Future<Output = R>, T>(
23 future: F,
24 spawn: impl FnOnce(future::Remote<future::Abortable<F>>) -> T,
25 ) -> Self {
26 let (abortable_future, abort_handle) = future::abortable(future);
27 let (task, output) = abortable_future.remote_handle();
28 let _ = spawn(task);
29 Self {
30 abort_handle,
31 output,
32 }
33 }
34
35 #[cfg(not(web))]
37 pub fn spawn<F: Future<Output = R> + Send + 'static>(future: F) -> Self
38 where
39 R: Send,
40 {
41 Self::spawn_(future, tokio::task::spawn)
42 }
43
44 #[cfg(web)]
46 pub fn spawn<F: Future<Output = R> + 'static>(future: F) -> Self {
47 Self::spawn_(future, wasm_bindgen_futures::spawn_local)
48 }
49
50 pub fn ready(value: R) -> Self {
52 Self::spawn_(async { value }, |fut| {
53 fut.now_or_never().expect("the future is ready")
54 })
55 }
56
57 pub async fn cancel(self) {
59 self.abort_handle.abort();
60 let _ = self.output.await;
61 }
62
63 pub fn forget(self) {
66 self.output.forget();
67 }
68}
69
70impl<R: 'static> std::future::IntoFuture for Task<R> {
71 type Output = R;
72 type IntoFuture = future::Map<
73 future::RemoteHandle<Result<R, future::Aborted>>,
74 fn(Result<R, future::Aborted>) -> R,
75 >;
76
77 fn into_future(self) -> Self::IntoFuture {
78 self.output
79 .map(|result| result.expect("we have the only AbortHandle"))
80 }
81}