通过WebAssembly将Rust的Vec<Vec<i32>>返回给JavaScript

3

我正在开发一个涉及Rust和WebAssembly的项目,使用"wasm32-unknown-unknown"目标。使用以下函数从我的Rust代码返回Vec<i32>没有问题:

#[no_mangle]
pub extern "C" fn calc_vector() -> usize {
    unsafe {
        vec_len = 0;
    }

    let mut data: Vec<i32> = Vec::new();

    for i in 0..1000 {
        data.push(i);
    }

    unsafe {
        vec_len = data.len();
    }

    data.as_mut_ptr() as usize
}

此函数返回一个偏移量,我从JS中调用另一个函数来获取我的Vec的长度。然后我再次在JavaScript中构建Vector(知道i32 -> 4x uint8):

let vec_addr = exports.calc_vector();
let vec_len = exports.get_vec_len();

while(arr.length < vec_len) {
    let numberUint8 = new DataView(view.buffer, vec_addr, 4);
    let number = numberUint8.getInt32(0, true);
    arr.push(number)

    // move to next value in vector
    vec_addr += 4;
}

我想创建一个Rust函数,返回一个Vec<Vec<i32>>,但是它却无法工作:

#[no_mangle]
pub extern "C" fn calc_vector_in_vector() -> usize {
    unsafe {
        vec_len = 0;
        elements_in_vect = 0;
    }

    let mut outer_vec: Vec<*mut i32> = Vec::new();
    let mut inner_vec: Vec<i32> = Vec::new();

    for i in 0..100 {
        inner_vec.push(i);
        unsafe {
            elements_in_vect += 1;
        }
    }

    outer_vec.push(inner_vec.as_mut_ptr());

    unsafe {
        vec_len = outer_vec.len();
    }

    outer_vec.as_mut_ptr() as usize
}

我认为我可以使用与单个Vec相同的逻辑:在从calc_vector_in_vector()返回的地址处是外部向量的第一个条目,它包含内部向量的第一个元素(实际数字)的地址。然而,在这个地址上似乎有些荒谬的东西。我在这里做错了什么?


3
我不确定第一个示例是如何工作的。您正在返回指向立即超出范围的值的指针。我没有使用过wasm,但我猜做法是在JavaScript中分配一个缓冲区,并从Rust中填充缓冲区。这样,JavaScript拥有数据并且它不会超出范围。 - Peter Hall
1
请查看如何从Rust在WebAssembly中返回字符串(或类似内容)?,以了解正确返回一个Vec的方法。 - Shepmaster
1个回答

1
因为我的向量中的向量长度都相同,所以我可以使用lazy_static crate来初始化一个静态的Vec,并用Mutex包装它(以便以后能够更改它)。LEN_VEC是向量的长度,SIZE_INNER_VEC是静态向量中一个向量的大小。
然后我将i32添加到静态向量中,并使用ARRAY.lock().unwrap().as_mut_ptr() as usize返回Vec的地址。通过SIZE_INNER_VECLEN_VEC,我可以在JavaScript中重新创建我的向量中的向量。
static mut LEN_VEC: usize = 0;
static mut SIZE_INNER_VEC: usize = 0;

lazy_static! {
    // Wrap in Mutex to change later on
    static ref ARRAY: Mutex<Vec<i32>> = Mutex::new(vec![]);
}

pub fn vector_in_vector() -> usize {
    //set LEN_VEC
    //set SIZE_INNER_VEC

    ARRAY.lock().unwrap().as_mut_ptr() as usize
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接