首页 文章

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

提问于
浏览
4

我想生成一个字节向量(在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在生命周期结束时( bytes 结束)函数丢弃了 Vec<u8> .

对不起,如果我错过了一些Wasm和Emscripten的基础知识,我今天只 Build 了我的第一个Wasm hello world .

2 回答

  • 1

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

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

    有两种类似的解决方案:

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

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

    我正在使用后者here .

  • 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 .

相关问题