wasm-tool/rollup-plugin-rust

How do I get accsess to the memory buffer

QuarkNerd opened this issue · 5 comments

Sorry if this is a silly question.

But I am able to access the classes/struct and the functions form inside my javascript (svelte). But I can't seem to see the memory buffer.

The memory buffer is normally exported by index_bg.wasm

Pauan commented

By default Wasm modules do not export anything, so you have to manually export the things that you want:

#[wasm_bindgen]
pub fn memory() -> JsValue {
    wasm_bindgen::memory()
}

Though you usually shouldn't need to access the memory buffer directly, what is your use case?

I can see export const memory: WebAssembly.Memory; and readonly memory: WebAssembly.Memory; in the ts files made in target and previously have been able to use memory without explicitly exporting it (when I wasn't using rollup).

If I try your suggestion I get

    0: failed to parse export section
    1: duplicate export name (at offset 3704)

My use case is to get the data for a display (simple on/off pixels, no colour) to render with JS.
Kind of like this tutorial (except Im making an emulator)

https://rustwasm.github.io/book/game-of-life/implementing.html#rendering-to-canvas-directly-from-memory

The tutorial suggests that rendering directly from memory is better than generating strrings to pass to JS

Pauan commented

You aren't supposed to use the values from index_bg.wasm since it's an implementation detail, and it will disappear after esm-integration is implemented.

If I try your suggestion I get

Ah, right, there's probably some sort of name conflict, so name it something else like wasm_memory.

The tutorial suggests that rendering directly from memory is better than generating strrings to pass to JS

That is very true, however you shouldn't be using the memory directly, since it requires you to mess around with the byte alignment and offset.

Instead, you should just have a Rust function/method which returns a Uint8Array and then you can use Uint8Array::view to send a Rust slice to JS:

#[wasm_bindgen]
pub fn get_slice(&self) -> Uint8Array {
    unsafe { Uint8Array::view(&self.my_slice) }
}

This does not copy the bytes (it just indexes directly into Wasm's memory), so it is very fast, but you have to uphold the safety guarantees.

The safety guarantees are quite simple: after you create the Uint8Array, you must not call any Rust functions until the JS code is done using the Uint8Array. Also, you must not access the Uint8Array after the slice is dropped.

If you don't want to deal with the unsafe requirements, you can instead use Uint8Array::from which will make a copy of the bytes. Even though it copies, this is still a lot faster than sending a string.

The Life tutorial is quite old (and outdated), it was created before Uint8Array::view existed. Nowadays there is almost no reason to use Wasm's memory, since you can just use Uint8Array::view instead (which does the same thing but far better).

In addition to Uint8Array, there is also Int8Array, Int16Array, Int32Array, Uint16Array, Uint32Array, Float32Array, and Float64Array.

Thank you very much for the help

Pauan commented

Of course.