4

I'm building a Chrome extension and I opted to use some WebAssembly functionality. I'm using wasm-pack to build the source because it provides a --target web that reduces the complexity of plugging in the Wasm functions. Passing integer values between Rust and JS works seamlessly, but I can't seem to be able to pass a string to Rust and vice versa.

Here is what I am working with:

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);

    #[wasm_bindgen(js_namespace = console)]
    fn log(x: &str);
} 

#[wasm_bindgen]
pub extern "C" fn add_two(x: i32) -> i32 {
   x + 2
}

#[wasm_bindgen]
pub fn hello(name: &str) {
    log("Hello") // <-- passing a '&str' directly works. I can see it in the browser.
    log(name) // <-- does not seem to work. There is no output
    alert(&format!("Hello {}", name)); // <- Only output im getting is "Hello !"
}

Update: More information on how i'm importing and instantiating wasm

After building with wasm-pack and importing the pkg directory generated into my JS folder. I make the contents of the pkg directory available to the project through the manifest.json file as a web_resource.

Here is how i'm loading the script in my content_script.js

(async function() {
  // Get the JS File
  const src = await import("/pkg/rusty.js");
  // Fetch the wasm file.
  const wasm_src = chrome.extension.getURL("/pkg/rusty_bg.wasm");
  //src has an exported function 'default' that initializes the WebAssembly module.
  let wasm = await src.default(wasm_src);

  wasm.hello("stack-overflow");
})();

I also noticed that my generated wasm_bg file has some Rust error output at the bottom . Error output in wasm_bg

8
  • Your question might be answered by the answers of How to return a string (or similar) from Rust in WebAssembly?. If not, please edit your question to explain the differences. Otherwise, we can mark this question as already answered. Commented Mar 2, 2020 at 20:26
  • There is a minimal difference in that the question posted doesn't use wasm-bindgen. Meaning I should be able to pass a string considering it does all the heavy work on my behalf. Commented Mar 2, 2020 at 20:32
  • All of options you've shown should definitely work; what seems to be the issue and not shown in the code above is how you're getting the wasm object that you're calling functions on. Make sure you're importing the main generated JavaScript module and not just the WebAssembly file directly. Commented Mar 12, 2020 at 18:10
  • @RReverser . I'm running this in a chrome extension. Meaning i had to use wasm-pack to get usable JS output that could easily be imported in my extension files. wasm-pack build --target web -- --features wee_alloc.Which output a pkg directory with JS that could be loaded in chrome without any import errors Commented Mar 14, 2020 at 15:29
  • @mar-tina That still doesn't show how you're getting the wasm object. Can you please update the code snippet to show how you're importing the generated package? Commented Mar 14, 2020 at 17:51

1 Answer 1

5

The issue is in how you're loading the code:

(async function() {
  // Get the JS File
  const src = await import("/pkg/rusty.js");
  // Fetch the wasm file.
  const wasm_src = chrome.extension.getURL("/pkg/rusty_bg.wasm");
  //src has an exported function 'default' that initializes the WebAssembly module.
  let wasm = await src.default(wasm_src);

  wasm.hello("stack-overflow");
})();

wasm returned from .default(...) is an object with raw WebAssembly exports that can operate only on raw numbers.

In this case what's happening is that wasm.hello expects two integer numbers - pointer and length of the string in WebAssembly memory - and JavaScript happily converts "stack-overflow" to 0 and provides another 0 as a default value, which is why you're ending up with an empty string on the Rust side.

What you want instead is the wrapped version of the function that takes care of proper conversions. These live directly on imports of the .js file:

(async function() {
  // Get the JS File
  const rusty = await import("/pkg/rusty.js");
  // Fetch the wasm file.
  const wasm_src = chrome.extension.getURL("/pkg/rusty_bg.wasm");
  // rusty has an exported function 'default' that initializes the WebAssembly module.
  await rusty.default(wasm_src);

  rusty.hello("stack-overflow"); // it works!
})();
Sign up to request clarification or add additional context in comments.

1 Comment

It’s worked! Many thanks. It took me a day to look for this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.