When using a vector of #[wasm_bindgen]
structs in javascript, is there a guarantee that the order of the struct's fields will be maintained so that bytes in wasm memory can be correctly interpreted in JS? I would like to be able to have a vector of structs in Rust and deterministically be able to reconstruct the structs on the JS side without having to serialize across the wasm boundary with serde. I have the following Rust code:
#[wasm_bindgen]
pub struct S {
a: u8,
b: u16,
}
#[wasm_bindgen]
pub struct Container {
ss: Vec<S>,
}
#[wasm_bindgen]
impl Container {
pub fn new() -> Self {
let ss = (0..10_u8)
.map(|i| S {
a: i,
b: (2 * i).into(),
})
.collect();
Self { ss }
}
pub fn items_ptr(&self) -> *const S {
self.ss.as_ptr()
}
pub fn item_size(&self) -> usize {
std::mem::size_of::<S>()
}
pub fn buffer_len(&self) -> usize {
self.ss.len() * self.item_size()
}
}
Now, on the JS side, I have the following:
import { memory } from "rust_wasm/rust_wasm.wasm";
import * as wasm from "rust_wasm";
const container = wasm.Container.new();
const items = new Uint8Array(memory.buffer, container.items_ptr(), container.buffer_len());
function getItemBytes(n) {
const itemSize = container.item_size();
const start = n * itemSize;
const end = start + itemSize;
return items.slice(start, end);
}
With the above code, I can obtain the (four, due to alignment) bytes that comprise an S
in JS. Now, my question: how do I interpret those bytes to reconstruct the S
(the fields a
and b
) in JS? In theory, I'd like to be able to say something like the following:
const itemBytes = getItemBytes(3);
const a = itemBytes[0];
const b = itemBytes[1] << 8 + itemBytes[2]
But of course this relies on the fact that the layout in memory of an instance of S
matches its definition, that u16
is big endian, etc. Is it possible to get Rust to enforce these properties so that I can safely interpret bytes in JS?