rust - 如何在 WebAssembly 中从 Rust 返回一个字符串(或类似字符串)?

标签 rust webassembly

我从这个 Rust 代码创建了一个小的 Wasm 文件:

#[no_mangle]
pub fn hello() -> &'static str {
    "hello from rust"
}

它构建并且可以从 JS 调用 hello 函数:

<!DOCTYPE html>
<html>
<body>
  <script>
    fetch('main.wasm')
    .then(response => response.arrayBuffer())
    .then(bytes => WebAssembly.instantiate(bytes, {}))
    .then(results => {
      alert(results.instance.exports.hello());
    });
  </script>
</body>
</html>

我的问题是 alert 显示“undefined”。如果我返回一个 i32,它会工作并显示 i32。我也尝试返回一个 String 但它不起作用(它仍然显示“未定义”)。

有没有办法在 WebAssembly 中从 Rust 返回一个字符串?我应该使用什么类型?

最佳答案

WebAssembly 只支持少数 numeric types ,这是可以通过导出函数返回的所有内容。

当您编译为 WebAssembly 时,您的字符串将保存在模块的线性内存中。为了从宿主 JavaScript 中读取这个字符串,你需要返回一个引用到它在内存中的位置,以及字符串的长度,即两个整数。这允许您从内存中读取字符串。

无论您将哪种语言编译成 WebAssembly,您都可以使用相同的技术。 How can I return a JavaScript string from a WebAssembly function提供问题的详细背景。

特别是对于 Rust,您需要使用外部函数接口(interface) (FFI),使用 CString 类型,如下所示:

use std::ffi::CString;
use std::os::raw::c_char;

static HELLO: &'static str = "hello from rust";

#[no_mangle]
pub fn get_hello() -> *mut c_char {
    let s = CString::new(HELLO).unwrap();
    s.into_raw()
}

#[no_mangle]
pub fn get_hello_len() -> usize {
    HELLO.len()
}

上面的代码导出了两个函数,get_hello 返回字符串的引用,get_hello_len 返回字符串的长度。

将上述代码编译成 wasm 模块后,可以按如下方式访问字符串:

const res = await fetch('chip8.wasm');
const buffer = await res.arrayBuffer();
const module = await WebAssembly.compile(buffer);
const instance = await WebAssembly.instantiate(module);

// obtain the module memory
const linearMemory = instance.exports.memory;

// create a buffer starting at the reference to the exported string
const offset = instance.exports.get_hello();
const stringBuffer = new Uint8Array(linearMemory.buffer, offset,
  instance.exports.get_hello_len());

// create a string from this buffer
let str = '';
for (let i=0; i<stringBuffer.length; i++) {
  str += String.fromCharCode(stringBuffer[i]);
}

console.log(str);

C 等价物 can be seen in action in a WasmFiddle .

关于rust - 如何在 WebAssembly 中从 Rust 返回一个字符串(或类似字符串)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50398348/

相关文章:

node.js - 如何使用 Create-React-App Node 服务器定义 MIME 类型?

emscripten - 将 C++ 函数编译为 Wasm

webpack - 如何将 WebAssembly (wasm) 与 create-react-app 一起使用

rust - 了解Rust中的引用生命周期

rust - 有没有办法在不可变地借用早期元素的同时向容器添加元素?

console - 在原始模式下使用 termion 时如何创建新行?

rust - 如何使用 wasm-bindgen 调用作为模块的 JavaScript 函数?

clang - 如何在wasm中更改导入模块名称 "env"?

rust - 编译 hyper 0.9.17 时出现 "macro undefined"错误

json - Rust使用Postgres JSON属性: cannot convert between the Rust type `alloc::string::String` and the Postgres type `jsonb`