Skip to main content

libsurfer/
async_util.rs

1/// Code related to asynchronous features.
2///
3/// As wasm32 and most other platforms behave differently, there are these wrappers.
4use futures_core::Future;
5use serde::Deserialize;
6use tracing::info;
7
8use crate::spawn;
9
10#[derive(Debug, Deserialize, PartialEq, Eq)]
11pub enum AsyncJob {
12    SaveState,
13    ExportFst,
14}
15
16#[cfg(all(not(target_arch = "wasm32"), feature = "https"))]
17pub(crate) fn ensure_rustls_crypto_provider() {
18    use std::sync::Once;
19
20    static INSTALL_PROVIDER: Once = Once::new();
21    INSTALL_PROVIDER.call_once(|| {
22        if rustls::crypto::CryptoProvider::get_default().is_none() {
23            rustls::crypto::ring::default_provider()
24                .install_default()
25                .expect("the Rustls crypto provider should only be installed once");
26        }
27    });
28}
29
30// Platform-dependent trait alias for futures that can be spawned
31#[cfg(target_arch = "wasm32")]
32pub trait SpawnableFuture: Future<Output = ()> + 'static {}
33#[cfg(target_arch = "wasm32")]
34impl<F> SpawnableFuture for F where F: Future<Output = ()> + 'static {}
35
36#[cfg(not(target_arch = "wasm32"))]
37pub trait SpawnableFuture: Future<Output = ()> + Send + 'static {}
38#[cfg(not(target_arch = "wasm32"))]
39impl<F> SpawnableFuture for F where F: Future<Output = ()> + Send + 'static {}
40
41// Wasm doesn't seem to support std::thread, so this spawns a thread where we can
42// but runs the work sequentially where we can not.
43pub fn perform_work<F>(f: F)
44where
45    F: FnOnce() + Send + 'static,
46{
47    spawn! {async {
48        info!("Starting async task");
49        f();
50    }}
51    info!("Returning from perform work");
52}
53
54// Spawn an async task on the appropriate runtime.
55// NOTE: wasm32 does not require a Send bound, but not-wasm32 does.
56pub fn perform_async_work<F>(f: F)
57where
58    F: SpawnableFuture,
59{
60    spawn!(f);
61}
62
63#[cfg(target_arch = "wasm32")]
64pub async fn sleep_ms(delay: u64) {
65    use wasm_bindgen_futures::js_sys;
66
67    let mut cb = |resolve: js_sys::Function, _reject: js_sys::Function| {
68        web_sys::window()
69            .unwrap()
70            .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, delay as i32)
71            .unwrap();
72    };
73
74    let p = js_sys::Promise::new(&mut cb);
75
76    wasm_bindgen_futures::JsFuture::from(p).await.unwrap();
77}
78
79#[cfg(not(target_arch = "wasm32"))]
80pub async fn sleep_ms(delay_ms: u64) {
81    tokio::time::sleep(tokio::time::Duration::from_millis(delay_ms)).await;
82}
83
84#[macro_export]
85macro_rules! spawn {
86    ($task:expr) => {
87        #[cfg(not(target_arch = "wasm32"))]
88        tokio::spawn($task);
89        #[cfg(target_arch = "wasm32")]
90        wasm_bindgen_futures::spawn_local($task);
91    };
92}