To understand WASM a little better, I want to try passing some string data from a Rust WASM module into JavaScript without using wasm_bindgen
. I am attempting to call a Rust function that returns a tuple containing a pointer to the string and its length. The module imports correctly, but I'm getting undefined
in the JS when I call the function.
I referred to this SO accepted answer, but it seems to be out-of-date and maybe a little unergonomic. The updated answer, of course, uses wasm_bindgen
. (Note: I'm not opposed to using wasm_bindgen
, I just want to understand what's going on better.)
My Rust:
use std::ptr;
#[no_mangle]
pub fn greet(name: &str) -> (u8, usize) {
let s = format!("Hello, {}!", name).to_string();
let len = s.len();
let ptr = ptr::addr_of!(s);
(ptr as u8, len)
}
Abbreviated JS:
let wasm = wasmModule.instance.exports;
//After WASM load:
console.log( wasm?.greet("WebAssembly") );
wasm.greet
, which I would then need to break apart and use to reference bytes in wasm.memory
, but I never get that ArrayBuffer.Based on this answer and confirmed by altering my own code, the problem was returning a tuple. You should return only a single value for the time being (apparently not all environments support returning multiple values).
So, the "unergonomic" code I mentioned seeing in this SO answer is actually necessary to some degree because you can't return a pointer and a length together.
JS code to get the string returned from separate function calls for the pointer and length:
function wasmString(loc, len) {
const mem = new Uint8Array(wasm?.memory?.buffer, loc, len);
console.log(mem);
const dec = new TextDecoder();
return dec.decode(mem);
}
Some other notes that may be helpful:
wasm_bindgen
magic. Investigating.