From f4299ff644ecfef5570f07e9ccede2459412a4bc Mon Sep 17 00:00:00 2001 From: Alex Wine Date: Tue, 20 Oct 2026 11:50:54 -0600 Subject: [PATCH] wasm: use the browser clock only on wasm32-unknown-unknown, not on WASI `now_ms` in layout, `now_unix` in engine, formats and pdf gated `js_sys::Date::now()` on `target_arch = "wasm32"`, which also matches wasm32-wasip1 and wasm32-wasip1-threads. There js-sys has no host to call, so it panics ("cannot call wasm-bindgen imported functions on non-wasm targets"), and since `layout()` times itself with `now_ms`, every document laid out on WASI aborts. `std::time` works on WASI, so these now use the browser clock only on wasm32-unknown-unknown, the gate wordcraft-docx already uses. --- crates/engine/Cargo.toml | 4 ++-- crates/engine/src/cmd/mod.rs | 4 ++-- crates/formats/Cargo.toml | 4 ++-- crates/formats/src/odt.rs | 4 ++-- crates/layout/Cargo.toml | 4 ++-- crates/layout/src/lib.rs | 4 ++-- crates/pdf/Cargo.toml | 4 ++-- crates/pdf/src/lib.rs | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/engine/Cargo.toml b/crates/engine/Cargo.toml index 17dac28de..bc5a6ee4f 100644 --- a/crates/engine/Cargo.toml +++ b/crates/engine/Cargo.toml @@ -28,8 +28,8 @@ regex-automata = { workspace = true } image = { workspace = true } zeroize = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -# The browser clock for `now_iso` (`SystemTime::now()` panics on wasm32). +[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] +# The browser clock for `now_iso` (`SystemTime::now()` panics on wasm32-unknown-unknown). js-sys = "0.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/crates/engine/src/cmd/mod.rs b/crates/engine/src/cmd/mod.rs index 5ccf5bf48..5191e1f10 100644 --- a/crates/engine/src/cmd/mod.rs +++ b/crates/engine/src/cmd/mod.rs @@ -427,12 +427,12 @@ pub fn iso_from_unix_secs(secs: u64) -> String { /// Seconds since the Unix epoch (UTC): the system clock, or the browser's on the web. pub fn now_unix() -> u64 { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] { std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|d| d.as_secs()).unwrap_or(0) } // `SystemTime::now()` panics on wasm32-unknown-unknown, so ask the browser's clock. - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { let ms = js_sys::Date::now(); // Clamp a NaN or pre-epoch clock to 0 rather than fail. diff --git a/crates/formats/Cargo.toml b/crates/formats/Cargo.toml index 6db6e4658..bfb3e0e55 100644 --- a/crates/formats/Cargo.toml +++ b/crates/formats/Cargo.toml @@ -19,8 +19,8 @@ encoding_rs = { workspace = true } chardetng = { workspace = true } log = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -# The browser clock (`SystemTime::now()` panics on wasm32): ODT change dates. +[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] +# The browser clock (`SystemTime::now()` panics on wasm32-unknown-unknown): ODT change dates. js-sys = "0.3" [dev-dependencies] diff --git a/crates/formats/src/odt.rs b/crates/formats/src/odt.rs index 2df9d4519..9552959cd 100644 --- a/crates/formats/src/odt.rs +++ b/crates/formats/src/odt.rs @@ -809,13 +809,13 @@ fn now_iso() -> String { /// Seconds since the Unix epoch: the system clock, or the browser's on the web. fn now_unix() -> i64 { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] { use std::time::{SystemTime, UNIX_EPOCH}; SystemTime::now().duration_since(UNIX_EPOCH).ok().and_then(|d| i64::try_from(d.as_secs()).ok()).unwrap_or(0) } // `SystemTime::now()` panics on wasm32-unknown-unknown, so ask the browser's clock. - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { let ms = js_sys::Date::now(); if ms.is_finite() && ms > 0.0 { (ms / 1000.0) as i64 } else { 0 } diff --git a/crates/layout/Cargo.toml b/crates/layout/Cargo.toml index afb8f0a4a..10bdb2d57 100644 --- a/crates/layout/Cargo.toml +++ b/crates/layout/Cargo.toml @@ -22,6 +22,6 @@ serde_json = { workspace = true } image = { workspace = true } log = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -# The browser clock (`SystemTime::now()`/`Instant::now()` panic on wasm32). +[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] +# The browser clock (`SystemTime::now()`/`Instant::now()` panic on wasm32-unknown-unknown). js-sys = "0.3" diff --git a/crates/layout/src/lib.rs b/crates/layout/src/lib.rs index a60c5f94d..e47764123 100644 --- a/crates/layout/src/lib.rs +++ b/crates/layout/src/lib.rs @@ -4571,13 +4571,13 @@ pub fn is_floating(o: &InlineObject) -> bool { /// Milliseconds since an arbitrary epoch (monotonic on native; the browser's clock on the web). pub fn now_ms() -> f64 { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] { static T0: std::sync::OnceLock = std::sync::OnceLock::new(); T0.get_or_init(std::time::Instant::now).elapsed().as_secs_f64() * 1000.0 } // `Instant::now()` panics on wasm32-unknown-unknown, so ask the browser's clock. - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { let ms = js_sys::Date::now(); if ms.is_finite() { ms } else { 0.0 } diff --git a/crates/pdf/Cargo.toml b/crates/pdf/Cargo.toml index d85446ed9..5431c39a2 100644 --- a/crates/pdf/Cargo.toml +++ b/crates/pdf/Cargo.toml @@ -20,8 +20,8 @@ image = { workspace = true } thiserror = { workspace = true } log = { workspace = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -# The browser clock (`SystemTime::now()` panics on wasm32). +[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] +# The browser clock (`SystemTime::now()` panics on wasm32-unknown-unknown). js-sys = "0.3" [dev-dependencies] diff --git a/crates/pdf/src/lib.rs b/crates/pdf/src/lib.rs index 7e853242e..4efb3be2e 100644 --- a/crates/pdf/src/lib.rs +++ b/crates/pdf/src/lib.rs @@ -443,14 +443,14 @@ fn parse_iso(s: &str) -> Option { /// The system clock, or the browser's on the web. fn now_unix() -> Option { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] { use std::time::{SystemTime, UNIX_EPOCH}; let secs = SystemTime::now().duration_since(UNIX_EPOCH).ok()?.as_secs(); i64::try_from(secs).ok() } // `SystemTime::now()` panics on wasm32-unknown-unknown, so ask the browser's clock. - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { let ms = js_sys::Date::now(); (ms.is_finite() && ms > 0.0).then(|| (ms / 1000.0) as i64)