javascriptrustwebassembly

Print a string from Rust WASM in JavaScript without wasm_bindgen


Problem

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.

Research

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.)

Code

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") );

Expectations and Assumptions


Solution

  • 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: