diff --git a/Cargo.toml b/Cargo.toml index d385b80..6a78e80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,9 @@ pinned = "0.1.0" once_cell = "1" [target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies] +js-sys = { version = "0.3" } +wasm-bindgen = { version = "0.2" } wasm-bindgen-futures = { version = "0.4" } -gloo = { version = "0.11" } [target.'cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))'.dependencies] tokio = { version = "1.35", features = ["rt", "time"] } diff --git a/src/rt_wasm_bindgen/time.rs b/src/rt_wasm_bindgen/time.rs index c34dea6..0912e70 100644 --- a/src/rt_wasm_bindgen/time.rs +++ b/src/rt_wasm_bindgen/time.rs @@ -7,7 +7,70 @@ use std::time::Duration; use futures::stream; use futures::stream::Stream; -use gloo::timers::callback::Timeout; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_name = "setTimeout", catch)] + fn set_timeout(handler: &js_sys::Function, timeout: i32) -> Result; + + #[wasm_bindgen(js_name = "clearTimeout")] + fn clear_timeout(handle: JsValue) -> JsValue; +} + +#[derive(Debug)] +#[must_use = "timeouts cancel on drop; either call `forget` or `drop` explicitly"] +struct Timeout { + id: Option, + closure: Option>, +} + +impl Drop for Timeout { + /// Disposes of the timeout, dually cancelling this timeout by calling + /// `clearTimeout` directly. + fn drop(&mut self) { + if let Some(id) = self.id.take() { + clear_timeout(id); + } + } +} + +impl Timeout { + /// Schedule a timeout to invoke `callback` in `millis` milliseconds from + /// now. + fn new(millis: u32, callback: F) -> Timeout + where + F: 'static + FnOnce(), + { + let closure = Closure::once(callback); + + let id = set_timeout( + closure.as_ref().unchecked_ref::(), + millis as i32, + ).unwrap_throw(); + + Timeout { + id: Some(id), + closure: Some(closure), + } + } + + /// Forgets this resource without clearing the timeout. + #[allow(dead_code)] + fn forget(mut self) -> JsValue { + let id = self.id.take().unwrap_throw(); + self.closure.take().unwrap_throw().forget(); + id + } + + /// Cancel this timeout so that the callback is not invoked after the time + /// is up. + #[allow(dead_code)] + fn cancel(mut self) -> Closure { + self.closure.take().unwrap_throw() + } +} #[inline(always)] pub(crate) fn sleep(dur: Duration) -> impl Future {