1use crate::{Executor, LocalExecutor, Task};
7use core::{
8 future::Future,
9 mem::ManuallyDrop,
10 pin::Pin,
11 task::{Context, Poll},
12};
13use wasm_bindgen_futures::spawn_local;
14
15#[derive(Clone, Copy, Debug)]
28pub struct WebExecutor;
29
30impl WebExecutor {
31 pub fn new() -> Self {
33 Self
34 }
35}
36
37impl Default for WebExecutor {
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43pub struct WebTask<T> {
49 inner: ManuallyDrop<Option<async_task::Task<T>>>,
50}
51
52impl<T> core::fmt::Debug for WebTask<T> {
53 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54 f.debug_struct("WebTask").finish_non_exhaustive()
55 }
56}
57
58impl<T> Future for WebTask<T> {
59 type Output = T;
60
61 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
62 let mut this = self.as_mut();
63 let task = this
64 .inner
65 .as_mut()
66 .expect("Task has already been cancelled");
67 let mut pinned_task = core::pin::pin!(task);
69 pinned_task.as_mut().poll(cx)
70 }
71}
72
73impl<T: 'static> Task<T> for WebTask<T> {
74 fn poll_result(
75 mut self: Pin<&mut Self>,
76 cx: &mut Context<'_>,
77 ) -> Poll<Result<T, crate::Error>> {
78 let mut this = self.as_mut();
79 let task = this
80 .inner
81 .as_mut()
82 .expect("Task has already been cancelled");
83 let mut pinned_task = core::pin::pin!(task);
86 match pinned_task.as_mut().poll(cx) {
87 Poll::Ready(value) => Poll::Ready(Ok(value)),
88 Poll::Pending => Poll::Pending,
89 }
90 }
91
92 fn poll_cancel(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
93 let this = unsafe { self.get_unchecked_mut() };
95 if let Some(task) = this.inner.take() {
96 wasm_bindgen_futures::spawn_local(async move {
98 let _ = task.cancel().await;
99 });
100 }
101 Poll::Ready(())
102 }
103}
104
105impl LocalExecutor for WebExecutor {
106 type Task<T: 'static> = WebTask<T>;
107
108 fn spawn<Fut>(&self, fut: Fut) -> Self::Task<Fut::Output>
109 where
110 Fut: Future + 'static,
111 {
112 let (runnable, task) = async_task::spawn_local(fut, |runnable: async_task::Runnable| {
113 spawn_local(async move {
114 runnable.run();
115 });
116 });
117 runnable.schedule();
118 WebTask {
119 inner: ManuallyDrop::new(Some(task)),
120 }
121 }
122}
123
124impl Executor for WebExecutor {
125 type Task<T: Send + 'static> = WebTask<T>;
126
127 fn spawn<Fut>(&self, fut: Fut) -> Self::Task<Fut::Output>
128 where
129 Fut: Future<Output: Send> + Send + 'static,
130 {
131 let (runnable, task) = async_task::spawn_local(fut, |runnable: async_task::Runnable| {
134 spawn_local(async move {
135 runnable.run();
136 });
137 });
138 runnable.schedule();
139 WebTask {
140 inner: ManuallyDrop::new(Some(task)),
141 }
142 }
143}