Wasm32-unknown-emscripten and async asset loading

I'd like to ask for advice regarding async assets loading when using wasm and Emscripten. As far as I can tell assets loading in the browser should be done asynchronously so I was wondering how would you do that for an application that also runs on other platforms (desktop, mobile)?

You can have different implementation of asset loading for each platform, e.g. by putting them in modules and using #[cfg()]:

#[cfg(target_arch = "wasm32")]
mod wasm;
#[cfg(target_arch = "wasm32")]
use wasm as imp;

#[cfg(windows)]
mod windows;
#[cfg(windows)]
use windows as imp;

…
    imp::load_assets().await

You can also choose at runtime by awaiting Box<dyn Future<Output=Asset>> type.

If you're worried about having to use sync filesystem functions on platforms that don't have async equivalents: you can use spawn_blocking for them, or just don't worry about it and hope local disk I/O is fast enough that blocking doesn't matter.

@kornel this seems like a good option. What I tried so far is something that looks like this:

thread_local!(static E : RefCell<Option<Box<Engine>>> = RefCell::new(None));

fn main2() {
    let e = Engine::new();

    E.with(|z| {
        *z.borrow_mut() = Some(Box::new(e));
    });

    #[cfg(not(target_arch = "wasm32"))]
    {
        E.with(|z| {
            if let Some(ref mut engine) = *z.borrow_mut() {
                futures::executor::block_on(engine.run_loop());
            }
        });
    }

    #[cfg(target_arch = "wasm32")]
    {
        set_main_loop_callback(move || {
            e.main_loop();
        });

        E.with(|z| {
            if let Some(ref mut engine) = *z.borrow_mut() {
                wasm_bindgen_futures::spawn_local(engine.run_loop());
            }
        });
    }
}

It works fine for the non-wasm32 target, but then it fails for wasm32.
And the error is the following:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:83:46
   |
83 |             if let Some(ref mut engine) = *z.borrow_mut() {
   |                                              ^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 82:16...
  --> src/main.rs:82:16
   |
82 |           E.with(|z| {
   |  ________________^
83 | |             if let Some(ref mut engine) = *z.borrow_mut() {
84 | |                 wasm_bindgen_futures::spawn_local(engine.run_loop());
85 | |             }
86 | |         });
   | |_________^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:83:44
   |
83 |             if let Some(ref mut engine) = *z.borrow_mut() {
   |                                            ^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `impl core::future::future::Future` will meet its required lifetime bounds
  --> src/main.rs:84:17
   |
84 |                 wasm_bindgen_futures::spawn_local(engine.run_loop());
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.

spawn can't make use of any temporary references. "valid for the static lifetime" means all temporary references are totally forbidden and can't be made to work.

Everything used inside spawn must either be exclusively owned by it (i.e. exist only in the spawn call, and be impossible to access from outside of it), or use Rc for shared ownership.

You probably want Rc<RefCell<Engine>> and lazy_static, or no globals at all, just init it as pass it down.

There's also a quirk where spawn(engine.run_loop()) may try to use a Future that borrows &self from engine, which isn't allowed. But async move { engine.run_loop().await } will work, because the async block owns the engine and it gets borrowed later after it's spawned.

You can request to fetch a resource. Once that comes back, JS sends an event to the Rust code containing the data.
The browser thread can't be blocked, but WebWorkers have access to blocking IO.

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