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/47529643/

相关文章:

rust - 从闭包调用可变方法时,无法推断autoref的生存期

rust - 从rust中的函数返回引用值

json - 有没有办法快速将 Json<Value> 转换为 bson 以便能够将其保存到 mongo?

rust - 具有部分移动错误的结构

arrays - 暂时将 [u8] 转化为 [u16]

rust - 如何在 Wasm (Rust) 中访问 JS 对象属性?

canvas - 直接从 WebAssembly 操作 Canvas 字节

javascript - 使用 Emscripten 将 JavaScript 字符串数组传递给 C 函数

compilation - 工具是否可用于 'assemble' WebAssembly 到 x86-64 native 代码?

webassembly - 是否可以向实例化的 Webassemble 模块添加新功能?