sauron_core/dom/
timeout.rs

1use crate::dom::window;
2use js_sys::Promise;
3use std::rc::Rc;
4use wasm_bindgen::closure::Closure;
5use wasm_bindgen::{JsCast, JsValue};
6use wasm_bindgen_futures::JsFuture;
7
8/// handle for request_idle_callback calls
9#[derive(Debug, Clone)]
10pub struct TimeoutCallbackHandle {
11    handle: i32,
12    _closure: Rc<Closure<dyn FnMut()>>,
13}
14
15impl Drop for TimeoutCallbackHandle {
16    fn drop(&mut self) {
17        window().clear_timeout_with_handle(self.handle);
18    }
19}
20
21/// request and idle callback
22pub fn request_timeout_callback<F>(f: F, timeout: i32) -> Result<TimeoutCallbackHandle, JsValue>
23where
24    F: FnMut() + 'static,
25{
26    let closure = Closure::once(f);
27    let handle = window().set_timeout_with_callback_and_timeout_and_arguments_0(
28        closure.as_ref().unchecked_ref(),
29        timeout,
30    )?;
31    Ok(TimeoutCallbackHandle {
32        handle,
33        _closure: Rc::new(closure),
34    })
35}
36
37/// simulate a delay using promise in js
38pub(crate) async fn async_delay(timeout: i32) -> Result<TimeoutCallbackHandle, JsValue> {
39    let mut result = Err(JsValue::NULL);
40    let promise = Promise::new(&mut |resolve, _reject| {
41        let handle = request_timeout_callback(
42            move || {
43                resolve
44                    .call0(&JsValue::NULL)
45                    .expect("must be able to call resolve");
46            },
47            timeout,
48        );
49        result = handle;
50    });
51    JsFuture::from(promise).await.expect("must not error");
52    result
53}
54
55/// wrapper of async delay but return no result, assume success
56pub async fn delay(timeout: i32) {
57    async_delay(timeout).await.expect("must not error");
58}