1#![deny(missing_debug_implementations)]
4#![warn(missing_docs)]
5
6mod suspense;
7
8use std::pin::Pin;
9use std::task::{Context, Poll};
10
11use futures::future::abortable;
12use futures::stream::Abortable;
13use futures::Future;
14use pin_project::pin_project;
15use sycamore_reactive::{on_cleanup, use_current_scope, NodeHandle};
16
17pub use self::suspense::*;
18
19pub async fn provide_executor_scope<U>(fut: impl Future<Output = U>) -> U {
22 #[cfg(all(target_arch = "wasm32", not(sycamore_force_ssr)))]
23 {
24 fut.await
25 }
26 #[cfg(any(not(target_arch = "wasm32"), sycamore_force_ssr))]
27 {
28 let local = tokio::task::LocalSet::new();
29 local.run_until(fut).await
30 }
31}
32
33pub fn spawn_local(fut: impl Future<Output = ()> + 'static) {
38 #[cfg(any(not(target_arch = "wasm32"), sycamore_force_ssr))]
39 tokio::task::spawn_local(fut);
40 #[cfg(all(target_arch = "wasm32", not(sycamore_force_ssr)))]
41 wasm_bindgen_futures::spawn_local(fut);
42}
43
44pub fn spawn_local_scoped(fut: impl Future<Output = ()> + 'static) {
50 let scoped = ScopedFuture::new_in_current_scope(fut);
51 spawn_local(scoped);
52}
53
54#[pin_project]
56struct ScopedFuture<T> {
57 #[pin]
58 task: Abortable<T>,
59 scope: NodeHandle,
60}
61
62impl<T: Future> Future for ScopedFuture<T> {
63 type Output = ();
64
65 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
66 let this = self.project();
67 this.scope.run_in(move || this.task.poll(cx).map(|_| ()))
68 }
69}
70
71impl<T: Future> ScopedFuture<T> {
72 pub fn new_in_current_scope(f: T) -> Self {
73 let (abortable, handle) = abortable(f);
74 on_cleanup(move || handle.abort());
75
76 let scope = use_current_scope();
77
78 Self {
79 task: abortable,
80 scope,
81 }
82 }
83}