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

时间:2017-08-17 03:06:09

标签: memory rust emscripten webassembly

我想在Rust中生成一个字节向量(Vec<u8>)并使用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。

2 个答案:

答案 0 :(得分:1)

与编写Rust相同的规则适用于此处。这意味着该函数必须返回一个拥有的值;当前它返回一个指向函数返回时丢弃的数据的指针。

一个人会返回Vec<u8>,其中包含(ptr,length,capacity),而且太大而无法返回C.

有两种类似的解决方案:

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

  2. 定义可从C。

  3. 访问的Vec

    我正在使用后者here

答案 1 :(得分:0)

好吧,所以在接受了@sebk的想法后(非常感谢指针)。 This is what I came up with.

它确实运作良好,所以我会很快描述它。我们需要一个表示我们可以从javacript访问一个数组,所以主要我们需要一个指针和数组的长度(用JsVec表示)。在wasm中你只能传递整数/浮点数,所以我们需要返回一个原始指针,Boxinto_raw所以我们可以返回一个指向我们JsVec的原始指针并获取信息。为了防止Rust丢弃我们的向量,我们需要使用mem::forget忘记向量。

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

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

再次感谢您帮助我。

编辑:

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

这很有效,而且我的浏览器也可以使用gist。