Is `std::time::Instant` on webassembly possible?

Now there are many crates relying on std::time::Insant for checking the duration or sleeping. For example, tokio::time::sleep directly relies on std::time::Instant.

However, whenever we try to use std::time::Instant on webassembly, a panic occurs.

panicked at 'time not implemented on this platform', /Users/username/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/

Other elements in std::time does seem to support webassembly. Only Instance does not support webassembly yet. Many crates are suffering from this problem and there are many crates that try to workaround this. Could support for webassebly be added for std::time::Instant?

Webassembly itself doesn't have any support for time. The host needs to provide this ability. There are three main host interfaces for Webassembly: Javascript/the web using wasm-bindgen, a POSIX like environment using Emscripten and a POSIX like environment using WASI. For both Emscripten and WASI libstd on the respective targets (wasm32-unknown-emscripten and wasm32-wasi) does support Instant::now(). For wasm-bindgen there is no separate target. Instead you have to use the generic wasm32-unknown-unknown target which works on any host. As such libstd for this target can't provide Instant::now(). You have to access the right javascript api using wasm-bindgen. I think the web-sys crate has the right binding using wasm-bindgen. In any case I don't think tokio will work in a browser. It can't provide an event loop (as the main thread isn't allowed to block), it can't provide fs access (as there is no fs) and it can't provide network access (as raw tcp and udp sockets aren't allowed by browsers). Instead you can use something like wasm-bindgen-future to adapt Javascript Promises to the rust Future interface to allow usage with async fn.

6 Likes

As I see it, the root problem here is that:

  • libraries want to implicitly know and be able to access things from the environment like the current time,
  • the usual mechanism by which to do so is the target triple, and
  • there is no unique target triple for web-using-wasm-bindgen.

The simplest solution that could start making this problem better is for there to be a target triple defined for the purpose — wasm32-unknown-wbindgen, say. That would help with libraries wanting to know “should I be talking to wasm-bindgen shims or something else?” which currently have to either provide feature flags for you to set or just assume every wasm32-unknown-unknown is wasm-bindgen-based — both of which are problematic.

But there's a problem: this would suggest that std should start implementing things like std::time::Instant on top of wasm-bindgen when that target is in use — but wasm-bindgen is a separate tool that does not ship as part of the Rust toolchain and which generates JS code in addition to Rust code. I don't know all the details here but I imagine it wouldn't be easy to cleanly bring that into the standard toolchain.

(rustc could support the triple without making any changes to std at all, so that libraries have something distinct to use in their cfgs, and I think that would be an improvement on the status quo — but weird.)

3 Likes

My understanding is that eventually wasm is intended to provide direct host bindings without JS glue through some mechanism, and if/when that's a thing we can have a wasm32-web target. Similarly, it's theoretically possible that a large enough group of people could create and endorse a standard set of bondings a la wasi but for the web that Rust could grow support that way. The reason wbindgen isn't quite that has to do with the extra postprocessing of the wasm that wbindgen requires alongside the host support; wasi doesn't require wasm postprocessing, only for the host functions to be provided.

web-sys and the like "just" use extern definitions which under wasm targets are turned into entries on an env map in the wasm imports that you provide when instantiating the module, just like exports are turned into entries on the wasm exports. So technically Rust could define an arbitrary required env map for some target (wasm32-unknown-env?), and you'd "just" have to provide those imports in whatever host you're using.

The main technical problems are:

  • Raw wasm is kind of annoying to interop with, especially anything where you're trying to implement object identity, so you're essentially requiring a JavaScript library to handle the other side (and the other side didn't have to be JavaScript!)
  • It's a whole bunch of API to design and document!
  • There's probably a bunch of stability concerns here: notably a missing import fails the instantiation.

I guess you could give it a try by forking the standard library and using xargo(?) to build it?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.