Передача строк между Rust и JavaScript при сборке с помощью wasm-pack - PullRequest
1 голос
/ 02 марта 2020

Я создаю расширение Chrome и решил использовать некоторые функции WebAssembly. Я использую wasm-pack для сборки исходного кода, потому что он обеспечивает --target web, что снижает сложность подключения функций Wasm. Передача целочисленных значений между Rust и JS работает без проблем, но я не могу передать строку в Rust и наоборот.

Вот то, с чем я работаю:

#[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 !"
}

Обновление: дополнительная информация о том, как я импортирую и создаю экземпляр wasm

После сборки с помощью wasm-pack и импорта каталога pkg, созданного в мою папку JS. Я делаю содержимое каталога pkg доступным для проекта через файл манифеста. json как web_resource.

Вот как я загружаю скрипт в свой файл 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");
})();

Я также заметил, что в моем сгенерированном файле wasm_bg есть некоторые сообщения об ошибках Rust внизу. Error output in wasm_bg

1 Ответ

1 голос
/ 17 марта 2020

Проблема заключается в том, как вы загружаете код:

(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, возвращаемое из .default(...) - это объект с необработанными экспортами WebAssembly, который может работать только с необработанными числами.

В этом случае происходит то, что wasm.hello ожидает два целых числа - указатель и длину строки в памяти WebAssembly - и JavaScript успешно преобразует "stack-overflow" в 0 и предоставляет еще один 0 по умолчанию значение, вот почему вы заканчиваете с пустой строкой на стороне Rust.

Вместо этого вам нужна свернутая версия функции, которая заботится о правильных преобразованиях. Они действуют непосредственно при импорте файла .js:

(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!
})();
...