1use crate::error::TimeoutError;
2use crate::global::BuiltinExecutor;
3use crate::{
4 AbortableJoinHandle, CommunicationTask, Executor, ExecutorBlockOn, ExecutorBlocking,
5 ExecutorTimeout, JoinHandle, Scope, ScopeExecutor, UnboundedCommunicationTask,
6};
7use futures::channel::mpsc::{Receiver, UnboundedReceiver};
8use parking_lot::{Condvar, Mutex};
9use std::sync::LazyLock;
10
11struct ExecutorState {
12 executor: BuiltinExecutor,
13 active: usize,
14}
15
16struct ExecutorLock {
17 state: Mutex<ExecutorState>,
18 available: Condvar,
19}
20
21static EXECUTOR: LazyLock<ExecutorLock> = LazyLock::new(|| ExecutorLock {
22 state: Mutex::new(ExecutorState {
23 executor: BuiltinExecutor::default(),
24 active: 0,
25 }),
26 available: Condvar::new(),
27});
28
29pub(crate) fn executor() -> BuiltinExecutor {
30 EXECUTOR.state.lock().executor
31}
32
33pub(crate) struct ExecutorGuard {
34 _private: (),
35}
36
37impl Drop for ExecutorGuard {
38 fn drop(&mut self) {
39 let mut state = EXECUTOR.state.lock();
40 state.active -= 1;
41 if state.active == 0 {
42 EXECUTOR.available.notify_all();
43 }
44 }
45}
46
47pub(crate) fn set_executor(executor: BuiltinExecutor) -> ExecutorGuard {
48 let mut state = EXECUTOR.state.lock();
49 while state.active != 0 && (state.executor != executor || executor.is_exclusive()) {
50 EXECUTOR.available.wait(&mut state);
51 }
52 if state.active == 0 {
53 state.executor = executor;
54 }
55 state.active += 1;
56 ExecutorGuard { _private: () }
57}
58
59pub fn runtime_type() -> Option<&'static str> {
61 executor().runtime_type()
62}
63
64pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
66where
67 F: Future + Send + 'static,
68 F::Output: Send + 'static,
69{
70 executor().spawn(future)
71}
72
73pub fn spawn_blocking<F, T>(future: F) -> JoinHandle<T>
74where
75 F: FnOnce() -> T + Send + 'static,
76 T: Send + 'static,
77{
78 executor().spawn_blocking(future)
79}
80
81pub fn spawn_abortable<F>(future: F) -> AbortableJoinHandle<F::Output>
87where
88 F: Future + Send + 'static,
89 F::Output: Send + 'static,
90{
91 executor().spawn_abortable(future)
92}
93
94pub fn spawn_timeout<F>(
98 duration: std::time::Duration,
99 future: F,
100) -> JoinHandle<Result<F::Output, TimeoutError>>
101where
102 F: Future + Send + 'static,
103 F::Output: Send + 'static,
104{
105 executor().spawn_timeout(duration, future)
106}
107
108pub fn spawn_delay<F>(duration: std::time::Duration, future: F) -> JoinHandle<F::Output>
110where
111 F: Future + Send + 'static,
112 F::Output: Send + 'static,
113{
114 executor().spawn_delay(duration, future)
115}
116
117pub fn spawn_abortable_timeout<F>(
122 duration: std::time::Duration,
123 future: F,
124) -> AbortableJoinHandle<Result<F::Output, TimeoutError>>
125where
126 F: Future + Send + 'static,
127 F::Output: Send + 'static,
128{
129 executor().spawn_abortable_timeout(duration, future)
130}
131
132pub fn spawn_abortable_delay<F>(
134 duration: std::time::Duration,
135 future: F,
136) -> AbortableJoinHandle<F::Output>
137where
138 F: Future + Send + 'static,
139 F::Output: Send + 'static,
140{
141 executor().spawn_abortable_delay(duration, future)
142}
143
144pub fn dispatch<F>(future: F)
147where
148 F: Future + Send + 'static,
149 F::Output: Send + 'static,
150{
151 executor().dispatch(future);
152}
153
154pub fn spawn_coroutine<T, F, Fut>(f: F) -> CommunicationTask<T>
158where
159 F: FnMut(T) -> Fut + Send + 'static,
160 Fut: Future<Output = ()> + Send + 'static,
161 T: Send + 'static,
162{
163 executor().spawn_coroutine(f)
164}
165
166pub fn spawn_coroutine_with_buffer<T, F, Fut>(buffer: usize, f: F) -> CommunicationTask<T>
170where
171 F: FnMut(T) -> Fut + Send + 'static,
172 Fut: Future<Output = ()> + Send + 'static,
173 T: Send + 'static,
174{
175 executor().spawn_coroutine_with_buffer(buffer, f)
176}
177
178pub fn spawn_unbounded_coroutine<T, F, Fut>(f: F) -> UnboundedCommunicationTask<T>
182where
183 F: FnMut(T) -> Fut + Send + 'static,
184 Fut: Future<Output = ()> + Send + 'static,
185 T: Send + 'static,
186{
187 executor().spawn_unbounded_coroutine(f)
188}
189
190pub fn spawn_coroutine_with_context<T, C, F, Fut>(context: C, f: F) -> CommunicationTask<T>
198where
199 F: FnMut(&mut C, T) -> Fut + Send + 'static,
200 Fut: Future<Output = ()> + Send + 'static,
201 C: Send + 'static,
202 T: Send + 'static,
203{
204 executor().spawn_coroutine_with_context(context, f)
205}
206
207pub fn spawn_coroutine_with_buffer_and_context<T, C, F, Fut>(
211 context: C,
212 buffer: usize,
213 f: F,
214) -> CommunicationTask<T>
215where
216 F: FnMut(&mut C, T) -> Fut + Send + 'static,
217 Fut: Future<Output = ()> + Send + 'static,
218 C: Send + 'static,
219 T: Send + 'static,
220{
221 executor().spawn_coroutine_with_buffer_and_context(context, buffer, f)
222}
223
224pub fn spawn_unbounded_coroutine_with_context<T, C, F, Fut>(
228 context: C,
229 f: F,
230) -> UnboundedCommunicationTask<T>
231where
232 F: FnMut(&mut C, T) -> Fut + Send + 'static,
233 Fut: Future<Output = ()> + Send + 'static,
234 C: Send + 'static,
235 T: Send + 'static,
236{
237 executor().spawn_unbounded_coroutine_with_context(context, f)
238}
239
240pub fn spawn_coroutine_with_receiver<T, F, Fut>(f: F) -> CommunicationTask<T>
244where
245 F: FnMut(Receiver<T>) -> Fut,
246 Fut: Future<Output = ()> + Send + 'static,
247{
248 executor().spawn_coroutine_with_receiver(f)
249}
250
251pub fn spawn_coroutine_with_receiver_and_buffer<T, F, Fut>(
255 buffer: usize,
256 f: F,
257) -> CommunicationTask<T>
258where
259 F: FnMut(Receiver<T>) -> Fut,
260 Fut: Future<Output = ()> + Send + 'static,
261{
262 executor().spawn_coroutine_with_receiver_and_buffer(buffer, f)
263}
264
265pub fn spawn_coroutine_with_receiver_and_context<T, F, C, Fut>(
269 context: C,
270 f: F,
271) -> CommunicationTask<T>
272where
273 F: FnMut(C, Receiver<T>) -> Fut,
274 Fut: Future<Output = ()> + Send + 'static,
275{
276 executor().spawn_coroutine_with_receiver_and_context(context, f)
277}
278
279pub fn spawn_coroutine_with_receiver_buffer_and_context<T, F, C, Fut>(
283 context: C,
284 buffer: usize,
285 f: F,
286) -> CommunicationTask<T>
287where
288 F: FnMut(C, Receiver<T>) -> Fut,
289 Fut: Future<Output = ()> + Send + 'static,
290{
291 executor().spawn_coroutine_with_receiver_buffer_and_context(context, buffer, f)
292}
293
294pub fn spawn_unbounded_coroutine_with_receiver<T, F, Fut>(f: F) -> UnboundedCommunicationTask<T>
298where
299 F: FnMut(UnboundedReceiver<T>) -> Fut,
300 Fut: Future<Output = ()> + Send + 'static,
301{
302 executor().spawn_unbounded_coroutine_with_receiver(f)
303}
304
305pub fn spawn_unbounded_coroutine_with_receiver_and_context<T, F, C, Fut>(
309 context: C,
310 f: F,
311) -> UnboundedCommunicationTask<T>
312where
313 F: FnMut(C, UnboundedReceiver<T>) -> Fut,
314 Fut: Future<Output = ()> + Send + 'static,
315{
316 executor().spawn_unbounded_coroutine_with_receiver_and_context(context, f)
317}
318
319pub fn scope<'env, F, T>(f: F) -> impl Future<Output = T>
324where
325 F: for<'scope> AsyncFnOnce(&'scope Scope<'scope, 'env>) -> T,
326{
327 crate::scoped::scope(f)
328}
329
330pub fn executor_scope<F, T>(f: F) -> impl Future<Output = T>
335where
336 F: for<'scope> AsyncFnOnce(&ScopeExecutor<'scope, BuiltinExecutor>) -> T,
337{
338 async move {
339 let executor = executor();
340 executor.executor_scope(f).await
341 }
342}
343
344pub fn block_on<F: Future>(f: F) -> F::Output {
348 executor().block_on(f)
349}
350
351#[cfg(not(all(feature = "tokio", not(target_arch = "wasm32"))))]
352#[derive(Default)]
353struct Yield {
354 yielded: bool,
355}
356
357#[cfg(not(all(feature = "tokio", not(target_arch = "wasm32"))))]
358impl core::future::Future for Yield {
359 type Output = ();
360
361 fn poll(
362 mut self: core::pin::Pin<&mut Self>,
363 cx: &mut core::task::Context<'_>,
364 ) -> core::task::Poll<()> {
365 if self.yielded {
366 return core::task::Poll::Ready(());
367 }
368 self.yielded = true;
369 cx.waker().wake_by_ref();
370 core::task::Poll::Pending
371 }
372}
373
374pub fn yield_now() -> impl Future<Output = ()> {
376 #[cfg(all(feature = "tokio", not(target_arch = "wasm32")))]
377 {
378 tokio::task::yield_now()
379 }
380 #[cfg(not(all(feature = "tokio", not(target_arch = "wasm32"))))]
381 {
382 Yield::default()
383 }
384}
385
386pub async fn yield_for(amount: usize) {
388 for _ in 0..amount {
389 yield_now().await;
390 }
391}