native_executor/
polyfill.rs

1//! Polyfill executor implementation using async-executor.
2
3use futures_lite::future::block_on;
4use std::{panic::catch_unwind, sync::OnceLock};
5
6use crate::PlatformExecutor;
7
8/// Polyfill executor implementation using async-executor.
9/// This executor is used on platforms that do not have a native executor implementation.
10#[derive(Debug, Clone, Copy, Default)]
11pub struct PolyfillExecutor;
12
13static EXECUTOR: OnceLock<async_executor::Executor<'static>> = OnceLock::new();
14
15fn global() -> &'static async_executor::Executor<'static> {
16    EXECUTOR.get_or_init(|| {
17        let exec = async_executor::Executor::new();
18        let num_threads = num_cpus::get().max(1);
19        for _ in 0..num_threads {
20            let executor = global();
21            std::thread::spawn(move || {
22                loop {
23                    let _ = catch_unwind(|| {
24                        block_on(executor.run(std::future::pending::<()>()));
25                    });
26                }
27            });
28        }
29        exec
30    })
31}
32
33static MAIN_EXECUTOR: OnceLock<async_executor::Executor<'static>> = OnceLock::new();
34
35/// Starts the main executor on a dedicated thread.
36/// This function is blocking and should be called once at the start of the program.
37///
38/// # Panics
39///
40/// Panics if the main executor has already been started.
41pub fn start_main_executor() {
42    let main_exec = async_executor::Executor::new();
43    MAIN_EXECUTOR
44        .set(main_exec)
45        .expect("Main executor already started");
46    let main_exec = MAIN_EXECUTOR
47        .get()
48        .expect("Unexpected error: main executor not set");
49    loop {
50        let _ = catch_unwind(|| {
51            block_on(main_exec.run(std::future::pending::<()>()));
52        });
53    }
54}
55
56fn main_executor() -> &'static async_executor::Executor<'static> {
57    MAIN_EXECUTOR.get().expect("Main executor not started")
58}
59
60impl PlatformExecutor for PolyfillExecutor {
61    fn exec(f: impl FnOnce() + Send + 'static, _priority: crate::Priority) {
62        global().spawn(async move { f() }).detach();
63    }
64    fn exec_after(
65        delay: std::time::Duration,
66        f: impl FnOnce() + Send + 'static,
67        _priority: crate::Priority,
68    ) {
69        global()
70            .spawn(async move {
71                async_io::Timer::after(delay).await;
72                f();
73            })
74            .detach();
75    }
76    fn exec_main(f: impl FnOnce() + Send + 'static) {
77        main_executor().spawn(async move { f() }).detach();
78    }
79}