0

Let me ask how to pass an array holding uint8 elements from javascript to wasm in Rust fast?

I found one method in: As JsValue.

Though I wonder if there is some clearly faster one when all element values are same primitive type and in a particular range.

For example, you encode a uint8 array to a string then pass the string to wasm not through JsValue.

Or I wonder if you can pass any array of primitive element type to wasm not through JsValues.

Edit: After reading the first answer, I tried to follow the answer with my understanding as follows. It seems to be successful. Is my understanding correct?


import * as wasm from "../pkg";
import * as bg_wasm from '../pkg/PACKAGE_NAME_bg.wasm';
const RUST_STRUCT = wasm.RUST_STRUCT.new();

const cellsPtr = RUST_STRUCT.cells();
const cells = new Uint8Array(bg_wasm.memory.buffer, cellsPtr, 100);
console.log( cells[50]);// 0
for(let i=0;i<100;i++){cells[i]=i;}
console.log( cells[50]);//50
console.log( "end");

Vec::leak

skatori
  • 547
  • 6
  • 20

1 Answers1

4

The WASM virtual machine has its own memory address space, that is seen from JS as a big ArrayBuffer usually named wasm.memory. Any value that you pass from JS to WASM has to be copied from its own variable to that memory.

But there is a nice trick. If you allocate a buffer from Rust side, such a Vec<u8>, and then somehow pass a reference to it to JS, then the &mut [u8] will become a JS Uint8Array, that is actually a direct view of the Rust memory. Zero copy overhead.

You just have to be careful not to use the reference from JS in a way that breaks any Rust invariant, such as passing it back as another reference, such that you get two &mut _ to the same value. Also you have to keep this memory alive in Rust for as long as JS holds the reference. It may even be a good idea to call Vec::leak() into your buffer so that its memory lives forever.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • Thank you very much for the answer. As a very beginner in this topic, I somehow read your text to encourage that my javascript can set new values on elements of the [u8] array if I am enough careful. Does it? – skatori Nov 18 '20 at 08:54
  • @skatori: Yes, correct. You have to be careful that you obey the Rust aliasing rules, though, that can be a bit tricky: basically you should only write to that buffer when Rust considers that it is mutably borrowed by the external code, such as calling a JS function from Rust and passing the `&mut [u8]`. Or alternatively, do `Vec::leak` in Rust, pass the reference to JS and forget that from Rust; then you can write from JS freely and pass to Rust slices of that memory. – rodrigo Nov 18 '20 at 12:26