openmina_core/
thread.rs

1#[cfg(not(target_arch = "wasm32"))]
2pub use std::thread::*;
3#[cfg(target_arch = "wasm32")]
4pub use wasm_thread::*;
5
6#[cfg(target_family = "wasm")]
7mod main_thread {
8    use crate::channels::{mpsc, oneshot};
9    use std::{future::Future, pin::Pin};
10
11    pub type TaskForMainThread = Pin<Box<dyn 'static + Send + Future<Output = ()>>>;
12
13    static MAIN_THREAD_TASK_SENDER: once_cell::sync::OnceCell<
14        mpsc::UnboundedSender<TaskForMainThread>,
15    > = once_cell::sync::OnceCell::new();
16
17    pub fn main_thread_init() {
18        assert!(
19            !super::is_web_worker_thread(),
20            "Must be called in the main thread!"
21        );
22
23        MAIN_THREAD_TASK_SENDER.get_or_init(|| {
24            let (task_sender, mut task_receiver) = mpsc::unbounded_channel();
25            wasm_bindgen_futures::spawn_local(async move {
26                while let Some(task) = task_receiver.recv().await {
27                    wasm_bindgen_futures::spawn_local(task);
28                }
29            });
30            task_sender
31        });
32    }
33
34    pub fn start_task_in_main_thread<F>(task: F)
35    where
36        F: 'static + Send + Future<Output = ()>,
37    {
38        let sender = MAIN_THREAD_TASK_SENDER
39            .get()
40            .expect("main thread not initialized");
41        let _ = sender.send(Box::pin(task));
42    }
43
44    pub async fn run_task_in_main_thread<F, T>(task: F) -> Option<T>
45    where
46        T: 'static + Send,
47        F: 'static + Send + Future<Output = T>,
48    {
49        let sender = MAIN_THREAD_TASK_SENDER
50            .get()
51            .expect("main thread not initialized");
52        let (tx, rx) = oneshot::channel();
53        let _ = sender.send(Box::pin(async move {
54            let _ = tx.send(task.await);
55        }));
56        rx.await.ok()
57    }
58
59    pub async fn run_async_fn_in_main_thread<F, FU, T>(f: F) -> Option<T>
60    where
61        T: 'static + Send,
62        FU: Future<Output = T>,
63        F: 'static + Send + FnOnce() -> FU,
64    {
65        let sender = MAIN_THREAD_TASK_SENDER
66            .get()
67            .expect("main thread not initialized");
68        let (tx, rx) = oneshot::channel();
69        let _ = sender.send(Box::pin(async move {
70            wasm_bindgen_futures::spawn_local(async move {
71                let _ = tx.send(f().await);
72            })
73        }));
74        rx.await.ok()
75    }
76
77    pub fn run_async_fn_in_main_thread_blocking<F, FU, T>(f: F) -> Option<T>
78    where
79        T: 'static + Send,
80        FU: Future<Output = T>,
81        F: 'static + Send + FnOnce() -> FU,
82    {
83        let sender = MAIN_THREAD_TASK_SENDER
84            .get()
85            .expect("main thread not initialized");
86        let (tx, rx) = oneshot::channel();
87        let _ = sender.send(Box::pin(async move {
88            wasm_bindgen_futures::spawn_local(async move {
89                let _ = tx.send(f().await);
90            })
91        }));
92        rx.blocking_recv().ok()
93    }
94}
95#[cfg(target_family = "wasm")]
96pub use main_thread::*;