能否无拷贝将WebAssembly::Memory转为Rust切片?跨DLL/WASM实现
WebAssembly Memory 转 Rust 原生切片的实现方案
要完成&WebAssembly::Memory到&mut [u8]/&[u8]的转换,核心是获取共享内存的起始指针和总字节长度,再通过unsafe操作构造Rust切片。以下是具体实现:
依赖配置
首先在Cargo.toml中添加必要依赖:
[dependencies] wasm-bindgen = "0.2" js-sys = "0.3"
完整代码实现
use wasm_bindgen::prelude::*; // 定义与JS WebAssembly.Memory对应的绑定类型 #[wasm_bindgen] extern "C" { #[derive(Clone, Debug)] type Memory; #[wasm_bindgen(method, getter)] fn buffer(this: &Memory) -> JsValue; } #[wasm_bindgen] pub fn write_to_shared_memory(mem: &Memory) { // 将Memory的buffer转为Uint8Array,方便获取指针和长度 let uint8_arr = js_sys::Uint8Array::new(&mem.buffer()); // 获取内存起始指针和总字节数 let ptr = uint8_arr.as_mut_ptr(); let len = uint8_arr.length() as usize; // 构造可变切片(unsafe操作,无有效性校验) let mem_slice = unsafe { std::slice::from_raw_parts_mut(ptr, len) }; write_impl(mem_slice); } // 核心逻辑:纯Rust实现,可直接用于DLL编译 pub fn write_impl(mem: &mut [u8]) { for i in 0..100 { mem[i] = i as u8; } } #[wasm_bindgen] pub fn read_from_shared_memory(mem: &Memory) -> JsValue { let uint8_arr = js_sys::Uint8Array::new(&mem.buffer()); let ptr = uint8_arr.as_ptr(); let len = uint8_arr.length() as usize; // 构造不可变切片 let mem_slice = unsafe { std::slice::from_raw_parts(ptr, len) }; read_impl(mem_slice).into() } // 核心逻辑:纯Rust实现 pub fn read_impl(arr: &[u8]) -> u8 { arr[0] }
关键步骤解析
- Memory绑定与buffer获取:通过
wasm_bindgen的extern块定义Memory类型,并绑定其buffergetter方法,拿到JS侧的ArrayBuffer。 - Uint8Array包装:用
js_sys::Uint8Array包装ArrayBuffer,它提供了直接获取内存指针和长度的API,比手动transmute更直观。 - 切片构造:
- 可变切片用
std::slice::from_raw_parts_mut,不可变用std::slice::from_raw_parts,这两个都是unsafe操作,因为Rust无法保证内存的合法性、生命周期和线程安全。
- 可变切片用
额外说明
- 无需使用
std::mem::transmute,Uint8Array的指针API已经足够完成转换,且可读性更强。 - 核心的
write_impl和read_impl完全基于原生Rust类型,剥离#[wasm_bindgen]相关代码后,可直接编译为DLL(需添加DLL导出属性,如#[no_mangle]等)。 - 如你所述,该操作存在极高风险:无边界检查、共享内存数据竞争、JS侧内存修改会导致Rust侧未定义行为,仅适合学习研究使用。
内容的提问来源于stack exchange,提问作者stevendesu
相关产品推荐
相关产品推荐

