-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std::time::SystemTime::now() causes panic on wasm32-unknown-unknown. #48564
Comments
It's weird that it seemingly panics with |
Thanks for the report! This is unfortunately, for now, an intended implementation detail of the standard library. The |
@alexcrichton , isn't this commit from Jan 30th should have resolved this issue completely? |
@hodlbank unfortunately that just added the possibility of another backend, but by default this still panics |
There is currently an implementation for |
Still panics on nightly. Poking at this there's 3 issues, if I'm understanding right:
|
@MaulingMonkey currently things are working as intended today. We're unlikely to ever stabilize the |
EDIT (2024-01-15): for anyone stumbling across this comment, consider using the Sweet, I'll try out WASI at some point. For anyone else who stumbles across this issue but isn't quite ready to switch away from #![allow(dead_code, unused_imports)]
use wasm_bindgen::prelude::*;
use std::convert::{TryInto};
use std::ops::{Add, Sub, AddAssign, SubAssign};
pub use std::time::*;
#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Instant(std::time::Instant);
#[cfg(not(target_arch = "wasm32"))] impl Instant {
pub fn now() -> Self { Self(std::time::Instant::now()) }
pub fn duration_since(&self, earlier: Instant) -> Duration { self.0.duration_since(earlier.0) }
pub fn elapsed(&self) -> Duration { self.0.elapsed() }
pub fn checked_add(&self, duration: Duration) -> Option<Self> { self.0.checked_add(duration).map(|i| Self(i)) }
pub fn checked_sub(&self, duration: Duration) -> Option<Self> { self.0.checked_sub(duration).map(|i| Self(i)) }
}
#[cfg(target_arch = "wasm32")] #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = Date, js_name = now)] fn date_now() -> f64; }
#[cfg(target_arch = "wasm32")] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Instant(u64);
#[cfg(target_arch = "wasm32")] impl Instant {
pub fn now() -> Self { Self(date_now() as u64) }
pub fn duration_since(&self, earlier: Instant) -> Duration { Duration::from_millis(self.0 - earlier.0) }
pub fn elapsed(&self) -> Duration { Self::now().duration_since(*self) }
pub fn checked_add(&self, duration: Duration) -> Option<Self> {
match duration.as_millis().try_into() {
Ok(duration) => self.0.checked_add(duration).map(|i| Self(i)),
Err(_) => None,
}
}
pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
match duration.as_millis().try_into() {
Ok(duration) => self.0.checked_sub(duration).map(|i| Self(i)),
Err(_) => None,
}
}
}
impl Add<Duration> for Instant { type Output = Instant; fn add(self, other: Duration) -> Instant { self.checked_add(other).unwrap() } }
impl Sub<Duration> for Instant { type Output = Instant; fn sub(self, other: Duration) -> Instant { self.checked_sub(other).unwrap() } }
impl Sub<Instant> for Instant { type Output = Duration; fn sub(self, other: Instant) -> Duration { self.duration_since(other) } }
impl AddAssign<Duration> for Instant { fn add_assign(&mut self, other: Duration) { *self = *self + other; } }
impl SubAssign<Duration> for Instant { fn sub_assign(&mut self, other: Duration) { *self = *self - other; } } |
So it compiles, but for sure doesn't run... and I stress again Rust compiles it. Edit: This is a misunderstanding on my part, compiled rust code is not garnered to be bug free. You have to deal with panics, throw renamed, and there are a few good ways to achieve this. |
I just spent days debugging coming to this. What is the workaround? Is it not possible to get the current timestamp in WASM? |
@Tails You have to use the code from #48564 (comment) though I wonder why it's not a crate... I can see where getting the time differs from wasm runtime to runtime, but I also see the target being used is |
Why does std::time::SystemTime::now() not fail when the target is wasm32-unknown-emscripten, but it does fail when the target is wasm32-unknown-unknown ? |
@crawlingChaos I think it's because the system type is emscripten and as such the API is known... emscripten has a libc/POSIX API, right? Where as with an unknown system designation the API is literally unknown. |
The code in #48564 (comment) is great, but missing an important detail. #48564 (comment) rewritten to use #![allow(dead_code, unused_imports)]
use wasm_bindgen::prelude::*;
use std::convert::{TryInto};
use std::ops::{Add, Sub, AddAssign, SubAssign};
pub use std::time::*;
#[cfg(not(target_arch = "wasm32"))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant(std::time::Instant);
#[cfg(not(target_arch = "wasm32"))]
impl Instant {
pub fn now() -> Self { Self(std::time::Instant::now()) }
pub fn duration_since(&self, earlier: Instant) -> Duration { self.0.duration_since(earlier.0) }
pub fn elapsed(&self) -> Duration { self.0.elapsed() }
pub fn checked_add(&self, duration: Duration) -> Option<Self> { self.0.checked_add(duration).map(|i| Self(i)) }
pub fn checked_sub(&self, duration: Duration) -> Option<Self> { self.0.checked_sub(duration).map(|i| Self(i)) }
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen(inline_js = r#"
export function performance_now() {
return performance.now();
}"#)]
extern "C" {
fn performance_now() -> f64;
}
#[cfg(target_arch = "wasm32")]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant(u64);
#[cfg(target_arch = "wasm32")]
impl Instant {
pub fn now() -> Self { Self((performance_now() * 1000.0) as u64) }
pub fn duration_since(&self, earlier: Instant) -> Duration { Duration::from_micros(self.0 - earlier.0) }
pub fn elapsed(&self) -> Duration { Self::now().duration_since(*self) }
pub fn checked_add(&self, duration: Duration) -> Option<Self> {
match duration.as_micros().try_into() {
Ok(duration) => self.0.checked_add(duration).map(|i| Self(i)),
Err(_) => None,
}
}
pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
match duration.as_micros().try_into() {
Ok(duration) => self.0.checked_sub(duration).map(|i| Self(i)),
Err(_) => None,
}
}
}
impl Add<Duration> for Instant { type Output = Instant; fn add(self, other: Duration) -> Instant { self.checked_add(other).unwrap() } }
impl Sub<Duration> for Instant { type Output = Instant; fn sub(self, other: Duration) -> Instant { self.checked_sub(other).unwrap() } }
impl Sub<Instant> for Instant { type Output = Duration; fn sub(self, other: Instant) -> Duration { self.duration_since(other) } }
impl AddAssign<Duration> for Instant { fn add_assign(&mut self, other: Duration) { *self = *self + other; } }
impl SubAssign<Duration> for Instant { fn sub_assign(&mut self, other: Duration) { *self = *self - other; } } Note: If you're targeting Node, it needs to be at least v8.5.0. |
Fixed the WASM crashes by reverting to wgpu = 0.14. This surfaced two more bugs in the repo for which I included fixes. A big issue is wasm32-unknown-unknown does not support std::time::Instant, so I implemented a polyfill based on rust-lang/rust#48564 (comment). The animated examples, SVG loader, and the frame statistics monitor won't work in WASM without this. Once there is progress on the wgpu end, I'll turn that into a proper PR.
Fixed the WASM crashes by reverting to wgpu = 0.14. This surfaced two more bugs in the repo for which I included fixes. A big issue is wasm32-unknown-unknown does not support std::time::Instant, so I implemented a polyfill based on rust-lang/rust#48564 (comment). The animated examples, SVG loader, and the frame statistics monitor won't work in WASM without this. Once there is progress on the wgpu end, I'll turn that into a proper PR. Other issues: * The WGSL won't compile on native since this version of wgpu/naga doesn't support `const`. Chrome Canary in WASM works though. * There are serious visual artifacts in the examples when run in the browser.
Fixed the WASM crashes by reverting to wgpu = 0.14. This surfaced two more bugs in the repo for which I included fixes. A big issue is wasm32-unknown-unknown does not support std::time::Instant, so I implemented a polyfill based on rust-lang/rust#48564 (comment). The animated examples, SVG loader, and the frame statistics monitor won't work in WASM without this. Once there is progress on the wgpu end, I'll turn that into a proper PR. Other issues: * The WGSL won't compile on native since this version of wgpu/naga doesn't support `const`. Chrome Canary in WASM works though. * There are serious visual artifacts in the examples when run in the browser.
Fixed the WASM crashes by reverting to wgpu = 0.14. This surfaced two more bugs in the repo for which I included fixes. A big issue is wasm32-unknown-unknown does not support std::time::Instant, so I implemented a polyfill based on rust-lang/rust#48564 (comment). The animated examples, SVG loader, and the frame statistics monitor won't work in WASM without this. Once there is progress on the wgpu end, I'll turn that into a proper PR. Also currently need to run the example with `cargo run_wasm --package with_winit --bin with_winit_bin` Other issues: * The WGSL won't compile on native since this version of wgpu/naga doesn't support `const`. Chrome Canary in WASM works though. * There are serious visual artifacts in the examples when run in the browser.
See rust-lang/rust#48564 for more information.
@cheako I am also facing same issue, adding the code above compiles fine but at runtime I am still getting "time not implemented" assert failed. how to fix it? |
@vivekvpandya This is a misunderstanding on my part, compiled rust code is not garnered to be bug free. You have to deal with panics, throw renamed, and there are a few good ways to achieve this. |
I've found https://crates.io/crates/web-time to be a good solution - it is a drop-in replacement for use web_time::{Instant, SystemTime};
let now = Instant::now();
let time = SystemTime::now(); |
Is it time we had a |
Hi.
Thank you guys for your great project.
I am trying wasm32-unknown-unknown and got an error(panic) in std::time::SystemTime::now().
Here is a reproduction code.
The error on Chrome on macOS. Similar error on Safari on macOS.
My environment is,
OS : macOS 10.13.3
Rust: rustc 1.26.0-nightly (322d7f7 2018-02-25)
Chrome: 64.0.3282.167
Sorry, I have no idea to confirm the version of wasm32-unknown-unknown.
Cheers.
The text was updated successfully, but these errors were encountered: