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