Wasm not returning string

I compiled the below code to wasm

// To call a JavaScript function
// 1. Define the JS functions signatures
extern {
    fn addOne(x: u32);
    fn alert(x: u32);
}
// 2. Call the JS function using unsafe block
#[no_mangle]
pub extern fn add_one(x: u32) {
    unsafe {
        addOne(x);
        alert(x);
    }
}

And called it smoothly with the below javascript

const result = wasmModule.instance.exports.add_one(5);

Then I wanted to use strings instead of numbers, but the returned of the process is always a number, never returned as string.

lib.rs:

use std::os::raw::{c_char};
use std::ffi::{CString, CStr};

// To call a JavaScript function
// 1. Define the JS functions signatures
extern {
    fn addOne(x: u32);
    fn alert(x: *mut c_char);
}
// 2. Call the JS function using unsafe block
#[no_mangle]
pub extern fn add_one(x: *const c_char, y: u32) {
    #[allow(unused_unsafe)]
    unsafe {
        addOne(y);
        let c_str = unsafe { CStr::from_ptr(x) };
        let recipient = match c_str.to_str() {
            Err(_) => "there",
            Ok(string) => string,
        };
        alert(CString::new(format!("{:?}` said: {}", x, y).to_owned() + recipient).unwrap().into_raw());
    }
}

cargo.toml:

[lib]
crate-type =["cdylib"]

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
      const addOne = (number) => {
        const text = document.createTextNode(number + 1);
        document.body.appendChild(text);
      }

      const importObject = {
        env: {
            addOne: addOne,
            alert: alert,
        }
      };

      WebAssembly.instantiateStreaming(fetch("utils.gc.wasm"), importObject)
      .then(wasmModule => {
           const result = wasmModule.instance.exports.add_one("Hasan", 5);
       })
    </script>
</head>
<body>
</body>
</html>

Note:
I executed the commands using:

$ cargo build --target wasm32-unknown-unknown --release
// $ cargo install wasm-gc
$ wasm-gc target/wasm32-unknown-unknown/release/utils.wasm -o utils.gc.wasm
// $ cargo install https
$ http

The output should be: Hasan said: 5
rwasm

Looks like this would be a lot easier with wasm_bindgen which supports the String type directly (String - The `wasm-bindgen` Guide). Natively, wasm only supports passing integers in and out, so if you want to use FFI, I think it's necessary to implement the copying and conversion from the wasm raw memory on the javascript side.

2 Likes