wasm_bindgen_futures/task/
singlethread.rs1use alloc::boxed::Box;
2use alloc::rc::Rc;
3use core::cell::{Cell, RefCell};
4use core::future::Future;
5use core::mem::ManuallyDrop;
6use core::pin::Pin;
7use core::task::{Context, RawWaker, RawWakerVTable, Waker};
8
9struct Inner {
10 future: Pin<Box<dyn Future<Output = ()> + 'static>>,
11 waker: Waker,
12}
13
14pub(crate) struct Task {
15 inner: RefCell<Option<Inner>>,
20
21 is_queued: Cell<bool>,
23}
24
25impl Task {
26 pub(crate) fn spawn(future: Pin<Box<dyn Future<Output = ()> + 'static>>) {
27 let this = Rc::new(Self {
28 inner: RefCell::new(None),
29 is_queued: Cell::new(true),
30 });
31
32 let waker = unsafe { Waker::from_raw(Task::into_raw_waker(Rc::clone(&this))) };
33
34 *this.inner.borrow_mut() = Some(Inner { future, waker });
35
36 crate::queue::Queue::with(|queue| queue.schedule_task(this));
37 }
38
39 fn force_wake(this: Rc<Self>) {
40 crate::queue::Queue::with(|queue| {
41 queue.push_task(this);
42 });
43 }
44
45 fn wake(this: Rc<Self>) {
46 if this.is_queued.replace(true) {
50 return;
51 }
52
53 Self::force_wake(this);
54 }
55
56 fn wake_by_ref(this: &Rc<Self>) {
57 if this.is_queued.replace(true) {
61 return;
62 }
63
64 Self::force_wake(Rc::clone(this));
65 }
66
67 unsafe fn into_raw_waker(this: Rc<Self>) -> RawWaker {
77 unsafe fn raw_clone(ptr: *const ()) -> RawWaker {
78 let ptr = ManuallyDrop::new(Rc::from_raw(ptr as *const Task));
79 Task::into_raw_waker(Rc::clone(&ptr))
80 }
81
82 unsafe fn raw_wake(ptr: *const ()) {
83 let ptr = Rc::from_raw(ptr as *const Task);
84 Task::wake(ptr);
85 }
86
87 unsafe fn raw_wake_by_ref(ptr: *const ()) {
88 let ptr = ManuallyDrop::new(Rc::from_raw(ptr as *const Task));
89 Task::wake_by_ref(&ptr);
90 }
91
92 unsafe fn raw_drop(ptr: *const ()) {
93 drop(Rc::from_raw(ptr as *const Task));
94 }
95
96 static VTABLE: RawWakerVTable =
97 RawWakerVTable::new(raw_clone, raw_wake, raw_wake_by_ref, raw_drop);
98
99 RawWaker::new(Rc::into_raw(this) as *const (), &VTABLE)
100 }
101
102 pub(crate) fn run(&self) {
103 let mut borrow = self.inner.borrow_mut();
104
105 let inner = match borrow.as_mut() {
108 Some(inner) => inner,
109 None => return,
110 };
111
112 self.is_queued.set(false);
115
116 let poll = {
117 let mut cx = Context::from_waker(&inner.waker);
118 inner.future.as_mut().poll(&mut cx)
119 };
120
121 if poll.is_ready() {
128 *borrow = None;
129 }
130 }
131}