Search code examples
rustwasm-bindgenwebassembly

How do I read a tuple struct from a Wasm memory buffer?


I have defined a tuple struct:

pub struct ChangedCell(pub bool, pub u32, pub u32);

My Assumption

ChangedCell weighs 9 bytes (bool: 1 byte, u32: 4 bytes, u32: 4 bytes)

What I Did

I returned a pointer, length for Vec<ChangedCell> to JavaScript:

const arr = new Uint8Array(memory.buffer, pointer, length * 9);
function getElements(n,arr) {

    const isVal = arr[n * 9 + 0];
    const val1 = arr.slice(n * 9 + 1, n * 9 + 5);
    const val2 = arr.slice(n * 9 + 5, n * 9 + 9);
    return {isVal,val1,val2}
}

Expected behaviour

  • isVal to be valid [byte]
  • val1 to be valid [byte] * 4
  • val2 to be valid [byte] * 4

Question

I am getting Garbage values! How do you read something like this into JavaScript?


Solution

  • First of all, if you are going to assume a particular layout you should mark your type as repr(C):

    #[repr(C)]
    pub struct ChangedCell(pub bool, pub u32, pub u32);
    

    It is likely that you get the same layout with our without the repr(C), but you only get a guarantee if you write it explicitly.

    Now you are guaranteed a C compatible layout, that (beware of the padding!) in wasm32 will be:

    • bool: at offset 0, 1 byte, 0x00 or 0x01.
    • u32: at offset 4, 4 bytes,
    • u32: at offset 8, 4 bytes,

    Total size: 12 bytes. Bytes 1, 2 and 3 are padding and thus unused.