use std::pin::pin;
use futures::future::{self as future_util, Either};
use js_sys::{Function, Promise, Reflect, global};
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen_futures::JsFuture;
pub use crate::common::time::{Duration, Instant, SystemTime, TimeoutError};
pub async fn sleep(duration: Duration) {
let ms = i32::try_from(duration.as_millis()).unwrap_or(i32::MAX);
let promise = Promise::new(&mut |resolve, _| {
let set_timeout: Function = Reflect::get(&global(), &JsValue::from_str("setTimeout"))
.expect("BUG: setTimeout is a standard browser global, must always exist")
.unchecked_into();
let _ = set_timeout.call2(&JsValue::UNDEFINED, &resolve, &JsValue::from(ms));
});
let _ = JsFuture::from(promise).await;
}
#[must_use]
pub fn coarse_now_ms() -> f64 {
js_sys::Date::now()
}
pub async fn timeout<F>(duration: Duration, future: F) -> Result<F::Output, TimeoutError>
where
F: Future,
{
let deadline = pin!(sleep(duration));
let work = pin!(future);
match future_util::select(work, deadline).await {
Either::Left((output, _)) => Ok(output),
Either::Right(((), _)) => Err(TimeoutError),
}
}