use js_sys::Function;
use wasm_bindgen::prelude::*;
use wasm_bindgen::{JsCast, JsValue};
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_name = "setTimeout", catch)]
fn set_timeout(handler: &Function, timeout: i32) -> Result<JsValue, JsValue>;
#[wasm_bindgen(js_name = "setInterval", catch)]
fn set_interval(handler: &Function, timeout: i32) -> Result<JsValue, JsValue>;
#[wasm_bindgen(js_name = "clearTimeout")]
fn clear_timeout(handle: JsValue) -> JsValue;
#[wasm_bindgen(js_name = "clearInterval")]
fn clear_interval(handle: JsValue) -> JsValue;
}
#[derive(Debug)]
#[must_use = "timeouts cancel on drop; either call `forget` or `drop` explicitly"]
pub struct Timeout {
id: Option<JsValue>,
closure: Option<Closure<dyn FnMut()>>,
}
impl Drop for Timeout {
fn drop(&mut self) {
if let Some(id) = self.id.take() {
clear_timeout(id);
}
}
}
impl Timeout {
pub fn new<F>(millis: u32, callback: F) -> Timeout
where
F: 'static + FnOnce(),
{
let closure = Closure::once(callback);
let id = set_timeout(
closure.as_ref().unchecked_ref::<js_sys::Function>(),
millis as i32,
)
.unwrap_throw();
Timeout {
id: Some(id),
closure: Some(closure),
}
}
pub fn forget(mut self) -> JsValue {
let id = self.id.take().unwrap_throw();
self.closure.take().unwrap_throw().forget();
id
}
pub fn cancel(mut self) -> Closure<dyn FnMut()> {
self.closure.take().unwrap_throw()
}
}
#[derive(Debug)]
#[must_use = "intervals cancel on drop; either call `forget` or `drop` explicitly"]
pub struct Interval {
id: Option<JsValue>,
closure: Option<Closure<dyn FnMut()>>,
}
impl Drop for Interval {
fn drop(&mut self) {
if let Some(id) = self.id.take() {
clear_interval(id);
}
}
}
impl Interval {
pub fn new<F>(millis: u32, callback: F) -> Interval
where
F: 'static + FnMut(),
{
let closure = Closure::wrap(Box::new(callback) as Box<dyn FnMut()>);
let id = set_interval(
closure.as_ref().unchecked_ref::<js_sys::Function>(),
millis as i32,
)
.unwrap_throw();
Interval {
id: Some(id),
closure: Some(closure),
}
}
pub fn forget(mut self) -> JsValue {
let id = self.id.take().unwrap_throw();
self.closure.take().unwrap_throw().forget();
id
}
pub fn cancel(mut self) -> Closure<dyn FnMut()> {
self.closure.take().unwrap_throw()
}
}