diff --git a/Cargo.toml b/Cargo.toml index e38f090..a242cac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "quanta" version = "0.12.3" authors = ["Toby Lawrence "] edition = "2021" -rust-version = "1.60" +rust-version = "1.70" license = "MIT" diff --git a/src/clocks/monotonic/mod.rs b/src/clocks/monotonic/mod.rs index b746333..80cbf89 100644 --- a/src/clocks/monotonic/mod.rs +++ b/src/clocks/monotonic/mod.rs @@ -3,10 +3,15 @@ mod windows; #[cfg(target_os = "windows")] pub use self::windows::Monotonic; -#[cfg(target_arch = "wasm32")] -mod wasm; -#[cfg(target_arch = "wasm32")] -pub use self::wasm::Monotonic; +#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] +mod wasm_browser; +#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] +pub use self::wasm_browser::Monotonic; + +#[cfg(all(target_arch = "wasm32", target_os = "wasi"))] +mod wasm_wasi; +#[cfg(all(target_arch = "wasm32", target_os = "wasi"))] +pub use self::wasm_wasi::Monotonic; #[cfg(not(any(target_os = "windows", target_arch = "wasm32")))] mod unix; diff --git a/src/clocks/monotonic/wasm.rs b/src/clocks/monotonic/wasm.rs deleted file mode 100644 index 39a742b..0000000 --- a/src/clocks/monotonic/wasm.rs +++ /dev/null @@ -1,27 +0,0 @@ -const WASM_WRONG_ENV: &str = "failed to find the global `window` object: the `wasm32-unknown-unknown` implementation only supports running in web browsers; wse `wasm32-wasi` to run elsewhere"; -const WASM_MISSING_WINDOW_PERF: &str = "failed to find `window.performance`"; - -#[derive(Clone, Copy, Debug, Default)] -pub struct Monotonic { - _default: (), -} - -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] -impl Monotonic { - pub fn now(&self) -> u64 { - let now = web_sys::window() - .expect(WASM_WRONG_ENV) - .performance() - .expect(WASM_MISSING_WINDOW_PERF) - .now(); - // `window.performance.now()` returns the time in milliseconds. - return f64::trunc(now * 1_000_000.0) as u64; - } -} - -#[cfg(all(target_arch = "wasm32", target_os = "wasi"))] -impl Monotonic { - pub fn now(&self) -> u64 { - unsafe { wasi::clock_time_get(wasi::CLOCKID_MONOTONIC, 1).expect("failed to get time") } - } -} diff --git a/src/clocks/monotonic/wasm_browser.rs b/src/clocks/monotonic/wasm_browser.rs new file mode 100644 index 0000000..b3f94a9 --- /dev/null +++ b/src/clocks/monotonic/wasm_browser.rs @@ -0,0 +1,39 @@ +use std::cell::OnceCell; + +use web_sys::{ + js_sys::Reflect, + wasm_bindgen::{JsCast, JsValue}, + Performance, +}; + +const WASM_MISSING_GLOBAL_THIS_PERF: &str = "failed to find `globalThis.performance`"; +const WASM_UNABLE_TO_CAST_PERF: &str = + "Unable to cast `globalThis.performance` to Performance type"; + +thread_local! { + static GLOBAL_PERFORMANCE_INSTANCE: OnceCell = const { OnceCell::new() }; +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct Monotonic { + _default: (), +} + +impl Monotonic { + pub fn now(&self) -> u64 { + let now = GLOBAL_PERFORMANCE_INSTANCE.with(|value| { + let performance_instance = value.get_or_init(|| { + Reflect::get( + &web_sys::js_sys::global(), + &JsValue::from_str("performance"), + ) + .expect(WASM_MISSING_GLOBAL_THIS_PERF) + .dyn_into::() + .expect(WASM_UNABLE_TO_CAST_PERF) + }); + performance_instance.now() + }); + // `performance.now()` returns the time in milliseconds. + f64::trunc(now * 1_000_000.0) as u64 + } +} diff --git a/src/clocks/monotonic/wasm_wasi.rs b/src/clocks/monotonic/wasm_wasi.rs new file mode 100644 index 0000000..f230f68 --- /dev/null +++ b/src/clocks/monotonic/wasm_wasi.rs @@ -0,0 +1,10 @@ +#[derive(Clone, Copy, Debug, Default)] +pub struct Monotonic { + _default: (), +} + +impl Monotonic { + pub fn now(&self) -> u64 { + unsafe { wasi::clock_time_get(wasi::CLOCKID_MONOTONIC, 1).expect("failed to get time") } + } +}