aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/executor/arch/wasm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/executor/arch/wasm.rs')
-rw-r--r--embassy-executor/src/executor/arch/wasm.rs74
1 files changed, 74 insertions, 0 deletions
diff --git a/embassy-executor/src/executor/arch/wasm.rs b/embassy-executor/src/executor/arch/wasm.rs
new file mode 100644
index 000000000..9d5aa31ed
--- /dev/null
+++ b/embassy-executor/src/executor/arch/wasm.rs
@@ -0,0 +1,74 @@
1use core::marker::PhantomData;
2
3use js_sys::Promise;
4use wasm_bindgen::prelude::*;
5
6use super::raw::util::UninitCell;
7use super::raw::{self};
8use super::Spawner;
9
10/// WASM executor, wasm_bindgen to schedule tasks on the JS event loop.
11pub struct Executor {
12 inner: raw::Executor,
13 ctx: &'static WasmContext,
14 not_send: PhantomData<*mut ()>,
15}
16
17pub(crate) struct WasmContext {
18 promise: Promise,
19 closure: UninitCell<Closure<dyn FnMut(JsValue)>>,
20}
21
22impl WasmContext {
23 pub fn new() -> Self {
24 Self {
25 promise: Promise::resolve(&JsValue::undefined()),
26 closure: UninitCell::uninit(),
27 }
28 }
29}
30
31impl Executor {
32 /// Create a new Executor.
33 pub fn new() -> Self {
34 let ctx = &*Box::leak(Box::new(WasmContext::new()));
35 let inner = raw::Executor::new(
36 |p| unsafe {
37 let ctx = &*(p as *const () as *const WasmContext);
38 let _ = ctx.promise.then(ctx.closure.as_mut());
39 },
40 ctx as *const _ as _,
41 );
42 Self {
43 inner,
44 not_send: PhantomData,
45 ctx,
46 }
47 }
48
49 /// Run the executor.
50 ///
51 /// The `init` closure is called with a [`Spawner`] that spawns tasks on
52 /// this executor. Use it to spawn the initial task(s). After `init` returns,
53 /// the executor starts running the tasks.
54 ///
55 /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
56 /// for example by passing it as an argument to the initial tasks.
57 ///
58 /// This function requires `&'static mut self`. This means you have to store the
59 /// Executor instance in a place where it'll live forever and grants you mutable
60 /// access. There's a few ways to do this:
61 ///
62 /// - a [Forever](crate::util::Forever) (safe)
63 /// - a `static mut` (unsafe)
64 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
65 pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
66 unsafe {
67 let executor = &self.inner;
68 self.ctx.closure.write(Closure::new(move |_| {
69 executor.poll();
70 }));
71 init(self.inner.spawner());
72 }
73 }
74}