我想在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在其生命周期结束时(Vec<u8>
)函数结束时删除了bytes
写入。
很抱歉,如果我错过了一些Wasm和Emscripten的基础知识,我今天只建立了我的第一个Wasm hello world。
答案 0 :(得分:1)
与编写Rust相同的规则适用于此处。这意味着该函数必须返回一个拥有的值;当前它返回一个指向函数返回时丢弃的数据的指针。
一个人会返回Vec<u8>
,其中包含(ptr,length,capacity),而且太大而无法返回C.
有两种类似的解决方案:
返回Box<Vec<u8>>
并定义另一个提取的函数
它的指针。
定义可从C。
Vec
醇>
我正在使用后者here。
答案 1 :(得分:0)
好吧,所以在接受了@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。