Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-core/src/async/wasm/executor.rs
StratoSDK / crates / strato-ui-core / src / async / wasm / executor.rs
1use std::sync::Arc;
2 
3use futures::{future::LocalBoxFuture, Future, FutureExt};
4use futures_util::future::{AbortHandle, Abortable};
5use wasm_bindgen_futures::spawn_local;
6 
7use crate::{platform, r#async::executor::Error};
8 
9/// A handle to a task that will run on the main thread.
10pub struct ForegroundTask;
11 
12impl ForegroundTask {
13 /// Detaches the task to let it keep running in the background.
14 pub fn detach(self) {}
15}
16 
17/// A handle to a task that will run in the background.
18///
19/// In practice, for wasm, this task will be executed on the singular main
20/// thread that all JavaScript code is run on.
21pub struct BackgroundTask;
22 
23impl BackgroundTask {
24 /// Detaches the task to let it keep running in the background.
25 pub fn detach(self) {}
26}
27 
28/// An executor that can be used to run tasks on the main thread.
29pub struct Foreground;
30 
31impl Foreground {
32 pub fn platform(_delegate: Arc<dyn platform::DispatchDelegate>) -> Result<Self, Error> {
33 Ok(Foreground)
34 }
35 
36 pub fn test() -> Self {
37 Foreground
38 }
39 
40 /// Schedule an asynchronous task to run on the main thread.
41 ///
42 /// If you have a boxed future, use `spawn_boxed` instead.
43 pub fn spawn(&self, future: impl Future<Output = ()> + 'static) -> ForegroundTask {
44 self.spawn_boxed(future.boxed_local())
45 }
46 
47 /// Schedule an asynchronous task to run on the main thread.
48 ///
49 /// This takes in a boxed future in order to avoid monomorphizing the
50 /// underlying task implementation. `spawn_boxed` generates significantly
51 /// less code than a generic implementation, with no noticeable performance
52 /// impact.
53 pub fn spawn_boxed(&self, future: LocalBoxFuture<'static, ()>) -> ForegroundTask {
54 spawn_local(future);
55 ForegroundTask
56 }
57 
58 /// Schedules an abortable asynchronous task to run on the main thread.
59 ///
60 /// This is the same as `spawn()` except the task may be aborted using the returned
61 /// [`AbortHandle`].
62 pub fn spawn_abortable(
63 &self,
64 future: impl Future<Output = ()> + 'static,
65 ) -> (ForegroundTask, AbortHandle) {
66 let (handle, registration) = AbortHandle::new_pair();
67 let task = self.spawn(Abortable::new(future, registration).map(|_| ()));
68 (task, handle)
69 }
70 
71 pub async fn run<T: 'static>(&'_ self, future: impl Future<Output = T> + 'static) -> T {
72 future.await
73 }
74}
75 
76/// An executor that can be used to run background tasks.
77///
78/// In practice, for wasm, these tasks will be executed on the singular main
79/// thread that all JavaScript code is run on.
80pub struct Background;
81 
82impl Default for Background {
83 fn default() -> Self {
84 Self::new()
85 }
86}
87 
88impl Background {
89 pub fn new() -> Self {
90 Background
91 }
92 
93 /// Schedule an asynchronous task to run on a background thread.
94 ///
95 /// If you have a boxed future, use `spawn_boxed` instead.
96 pub fn spawn(&self, future: impl Future<Output = ()> + 'static) -> BackgroundTask {
97 self.spawn_boxed(future.boxed_local())
98 }
99 
100 /// Schedule an asynchronous task to run on a background thread.
101 ///
102 /// This takes in a boxed future in order to avoid monomorphizing the
103 /// underlying task implementation. `spawn_boxed` generates significantly
104 /// less code than a generic implementation, with no noticeable performance
105 /// impact.
106 pub fn spawn_boxed(&self, future: LocalBoxFuture<'static, ()>) -> BackgroundTask {
107 spawn_local(future);
108 BackgroundTask
109 }
110 
111 /// Schedules an abortable asynchronous task to run on a background thread.
112 ///
113 /// This is the same as `spawn()` except the task may be aborted using the returned
114 /// [`AbortHandle`].
115 pub fn spawn_abortable(
116 &self,
117 future: impl Future<Output = ()> + 'static,
118 ) -> (BackgroundTask, AbortHandle) {
119 let (handle, registration) = AbortHandle::new_pair();
120 let task = self.spawn(Abortable::new(future, registration).map(|_| ()));
121 (task, handle)
122 }
123}
124