我想生成一个字节向量(在Rust中为 Vec<u8>
),并使用JS作为 Array
或 Uint8Array
访问它,并将其发送到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 回答
与编写Rust相同的规则适用于此处 . 这意味着该函数必须返回一个拥有的值;当前它返回一个指向函数返回时丢弃的数据的指针 .
一个人会返回
Vec<u8>
,其中包含(ptr,length,capacity)并且太大而无法返回C.有两种类似的解决方案:
返回
Box<Vec<u8>>
并定义另一个从中提取指针的函数 .定义您自己的
Vec
,可从C访问 .我正在使用后者here .
好吧,所以从@sebk获取想法后(非常感谢指针) . This is what I came up with.
它实际上运作良好,所以我会很快描述它 . 我们需要一个表示我们可以从javacript访问一个数组,所以主要我们需要一个指针和数组的长度(在
JsVec
中表示) . 在wasm中你只能传递整数/浮点数,所以我们需要返回一个原始指针,Box
有into_raw
所以我们可以返回一个指向我们JsVec
的原始指针并获取信息 . 为了防止Rust丢弃我们的向量,我们需要忘记向量,使用mem::forget
.在javascript世界中,它就像通过指针和
Module.HEAPU32
值访问堆上的数据一样简单 .下一个问题是删除了向量,所以我们使用原始指针并从中创建一个自动删除的
Box
,据我所知,它会删除JsVec
对象,但不会删除vec或内容 . 这是它可能出错的主要区域,这是内存泄漏吗?或者放弃JsVec
就足够了 .再次感谢帮助我 .
编辑:
好极了!我似乎已经使它工作(要点已更新) . 我拿了this reddit comment's advice并从
JsBytes
(重命名)struct构造了一个向量,以确保向量本身被删除!这有效,并且我的浏览器可以使用gist .