executor_core/
web.rs

1//! Integration for Web/WASM environments.
2//!
3//! This module provides executor implementations for web browsers and other
4//! WASM environments using `wasm-bindgen-futures`.
5
6use crate::{Executor, LocalExecutor, Task};
7use core::{
8    future::Future,
9    pin::Pin,
10    task::{Context, Poll},
11};
12use wasm_bindgen_futures::spawn_local;
13
14
15/// Web-based executor implementation for WASM targets.
16///
17/// This executor uses `wasm-bindgen-futures::spawn_local` to execute futures
18/// in web environments. Both `Send` and non-`Send` futures are handled the same
19/// way since web environments are single-threaded.
20///
21/// ## Panic Handling
22///
23/// Unlike other executors, the web executor cannot catch panics due to WASM limitations.
24/// If a spawned task panics, the entire WASM module will terminate. This is a fundamental
25/// limitation of the WASM environment and cannot be worked around.
26///
27#[derive(Clone, Copy, Debug)]
28pub struct WebExecutor;
29
30impl WebExecutor {
31    /// Create a new [`WebExecutor`].
32    pub fn new() -> Self {
33        Self
34    }
35}
36
37impl Default for WebExecutor {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43/// Task wrapper for web/WASM environment.
44///
45/// This task type provides task management for web environments where
46/// panic catching is not available. Unlike other task implementations,
47/// panics cannot be caught and will terminate the entire WASM module.
48///
49/// This is a simple wrapper that just awaits the spawned future directly.
50pub struct WebTask<T> {
51    _marker: core::marker::PhantomData<T>,
52}
53
54impl<T> core::fmt::Debug for WebTask<T> {
55    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
56        f.debug_struct("WebTask").finish_non_exhaustive()
57    }
58}
59
60impl<T: 'static> WebTask<T> {
61    fn new() -> Self {
62        Self {
63            _marker: core::marker::PhantomData,
64        }
65    }
66}
67
68impl<T> Future for WebTask<T> {
69    type Output = T;
70
71    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
72        // Web tasks complete immediately since they're spawned via spawn_local
73        // This shouldn't actually be called since we don't store the future
74        Poll::Pending
75    }
76}
77
78impl<T: 'static> Task<T> for WebTask<T> {
79    fn poll_result(
80        self: Pin<&mut Self>,
81        _cx: &mut Context<'_>,
82    ) -> Poll<Result<T, crate::Error>> {
83        // Web tasks complete immediately since they're spawned via spawn_local
84        // This shouldn't actually be called since we don't store the future
85        Poll::Pending
86    }
87
88    fn poll_cancel(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
89        // In web environment, tasks can't be cancelled once spawned
90        Poll::Ready(())
91    }
92}
93
94
95impl LocalExecutor for WebExecutor {
96    type Task<T: 'static> = WebTask<T>;
97
98    fn spawn_local<Fut>(&self, fut: Fut) -> Self::Task<Fut::Output>
99    where
100        Fut: Future + 'static,
101    {
102        // Spawn the future directly using wasm-bindgen-futures
103        // We need to wrap it to discard the result since spawn_local expects ()
104        spawn_local(async move {
105            let _ = fut.await;
106        });
107        
108        // Return a placeholder task since web tasks can't be awaited
109        WebTask::new()
110    }
111}
112
113impl Executor for WebExecutor {
114    type Task<T: Send + 'static> = WebTask<T>;
115
116    fn spawn<Fut>(&self, fut: Fut) -> Self::Task<Fut::Output>
117    where
118        Fut: Future<Output: Send> + Send + 'static,
119    {
120        // In web environment, we use spawn_local even for Send futures
121        // since web workers don't have the same threading model as native
122        // Spawn the future directly using wasm-bindgen-futures
123        // We need to wrap it to discard the result since spawn_local expects ()
124        spawn_local(async move {
125            let _ = fut.await;
126        });
127        
128        // Return a placeholder task since web tasks can't be awaited
129        WebTask::new()
130    }
131}