4

I want to generate a vector of bytes (Vec<u8> in Rust) and access it with JS as an Array or Uint8Array and send it to a WebSocket or to IndexedDB.

I found How can I pass an array from JavaScript to Rust that has been compiled with Emscripten?, which is the exact opposite of what I would like to do, but very relevant. Other than that, I am aware of the array type in Emscripten, but I am not aware how to correctly use it.

My best guess on how to get this working was to try returning the vector as_mut_ptr, and use the pointer on the Module.HEAPU8.

main.rs

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

fn main() {}

Part of 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());
}

The results of the console ended up looking like this:

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

The first issue is that both values represent empty arrays, and second the two separate calls are pointing to the same memory location. I have absolutely no idea how to access pointed to data on the heap, along with the length of the vector.

The two pointers pointing to the same memory location could be because Rust drops the Vec<u8> write when it's lifetime ends, (end of the bytes) function.

Sorry if I missed some basics of Wasm and Emscripten, I only built my first Wasm hello world today.

4

2 回答 2

1

与编写 Rust 相同的规则在这里适用。这意味着函数必须返回一个拥有的值;目前它返回一个指向函数返回时删除的数据的指针。

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

有两种类似的解决方案:

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

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

我在这里使用后者。

于 2017-08-17T08:41:09.573 回答
0

好的,所以在从@sebk 获得想法之后(非常感谢您的指点)。这就是我想出的。

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

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

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

再次感谢您帮助我。

编辑:

耶!我似乎已经让它工作了(要点已更新)。我接受了这个 reddit 评论的建议,并从JsBytes(重命名的)结构构造了一个向量,以确保向量本身被删除!

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

于 2017-08-17T18:01:26.173 回答