从编译为 Emscripten 的 Rust 获取 Javascript 中的数组

Getting an array in Javascript from Rust compiled to Emscripten

我想生成一个字节向量(Vec<u8> 在 Rust 中)并使用 JS 作为 ArrayUint8Array 访问它并将它发送到 WebSocket 或 IndexedDB。

我发现 How can I pass an array from JavaScript to Rust that has been compiled with Emscripten?,这与我想做的完全相反,但非常相关。除此之外,我知道 Emscripten 中的数组类型,但我不知道如何正确使用它。

我最好的猜测是尝试返回向量 as_mut_ptr,并使用 Module.HEAPU8 上的指针。

main.rs

#[no_mangle]
pub fn bytes() -> *mut u8 {
    vec![1, 2, 3].as_mut_ptr()
}

fn main() {}

index.html

的一部分
var Module = {
    wasmBinaryFile: "site.wasm",
    onRuntimeInitialized: main,
};
function main() {
    let ptr = Module._bytes();
    console.log(ptr);
    console.log(Module.HEAPU8.slice(ptr, ptr + 10));
    console.log(Module.HEAPU8.subarray(ptr, ptr + 100));
    let arr = Module.cwrap('bytes', 'array', []);
    console.log(arr());
}

控制台的结果最终如下所示:

5260296  site:11:13
Uint8Array [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]  site:12:13
Uint8Array [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90 more… ]  site:13:13
5260296  site:15:13

第一个问题是两个值都表示空数组,第二个问题是两个单独的调用指向相同的内存位置。我完全不知道如何访问堆上指向的数据以及向量的长度。

指向同一内存位置的两个指针可能是因为 Rust 在其生命周期结束时丢弃 Vec<u8> 写入,(bytes 函数结束)。

抱歉,如果我错过了 Wasm 和 Emscripten 的一些基础知识,我今天才构建了我的第一个 Wasm hello world。

此处适用与编写 Rust 相同的规则。这意味着该函数必须 return 一个拥有的值;目前它 returns 是一个指向数据的指针,当函数 returns.

一个会 return Vec<u8> 由 (ptr, length, capacity) 组成并且太大以至于 return 到 C.

有两个类似的解决方案:

  1. return Box<Vec<u8>> 并定义另一个函数来提取 来自它的指针。

  2. 定义您自己的 Vec 可从 C 访问。

我用的是后者here.

好的,所以在从@sebk 那里得到想法之后(非常感谢您的指点)。 This is what I came up with.

它实际上很好用,所以我将快速描述它。我们需要一个可以从 javacript 访问数组的表示,所以我们主要需要一个指针和数组的长度(在 JsVec 中表示)。在 wasm 中你只能传递 integers/floats,所以我们需要 return 一个原始指针,Boxinto_raw 所以我们可以 return 一个指向我们的原始指针JsVec 并获取信息。为了防止 Rust 丢弃我们的向量,我们需要忘记向量,使用 mem::forget.

在javascript 世界中,它就像通过指针和Module.HEAPU32 值访问堆上的数据一样简单。

下一个问题是 vector 的删除,所以我们使用原始指针并从中创建一个 Box,它会自动删除,据我所知,它会删除 JsVec 对象,但是不是 vec 或内容。这是它可能出错的主要区域,所以这会导致内存泄漏吗?或者删除 JsVec 就足够了。

再次感谢您帮助我。

编辑:

耶!我似乎已经让它工作了(要点已更新)。我采用 this reddit comment's advice 并从 JsBytes (重命名)结构构建了一个向量,以确保向量本身被删除!

这有效,要点在我的浏览器中有效。