In JavaScript, I'm trying to loop over a vector of structs created in Rust without copying the data (serialize -> send -> deserialize). I followed the WASM Game of Life tutorial, but it only brushes over working with memory. I'm not able to figure out how to go from working with an exact set of u8
s like they do, to working with an arbitrary set of structs where not all fields are u8
s.
My project files are the same as the tutorial's, except the following.
Rust
use {std::ops, wasm_bindgen::prelude::*};
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum DiagnosticSeverity {
Err = 1,
Warn = 2,
Info = 3,
Hint = 4,
}
#[wasm_bindgen]
pub struct Diagnostic {
range: ops::Range<usize>,
message: String,
severity: DiagnosticSeverity,
}
#[wasm_bindgen]
impl Diagnostic {
pub fn new() -> Self {
Diagnostic {
// Randomly selected to see if I can
// recognize them in JavaScript
range: 30..544,
message: "Test diagnostic".to_string(),
severity: DiagnosticSeverity::Info,
}
}
pub fn msg(&self) -> String {
self.message.to_owned()
}
pub fn severity(&self) -> DiagnosticSeverity {
self.severity
}
}
#[wasm_bindgen]
pub struct DiagList {
items: Vec<Diagnostic>,
}
#[wasm_bindgen]
impl DiagList {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn push(&mut self) {
self.items.push(Diagnostic {
// Get different values for testing purposes
range: self.len()..self.len() + 3,
message: format!("Diag#{}", self.len()),
// In JS, I `push()` twice and want each to have a
// different value for testing purposes
severity: if self.len() % 2 == 0 {
DiagnosticSeverity::Info
} else {
DiagnosticSeverity::Hint
},
});
}
pub fn items(&self) -> *const Diagnostic {
self.items.as_ptr()
}
pub fn buffer_len(&self) -> usize {
self.items.len() * std::mem::size_of::<Diagnostic>()
}
pub fn len(&self) -> usize {
self.items.len()
}
}
JavaScript (index.js)
import { DiagList, Diagnostic, DiagnosticSeverity } from "wasm_test/wasm_test";
import { memory } from 'wasm_test/wasm_test_bg'
const list = DiagList.new();
const listItemsPtr = list.items();
list.push()
list.push()
const listItems = new Uint8Array(memory.buffer, listItemsPtr, list.len());
console.log(listItems);
The above JavaScript will log [0, 0]
, which I guess are null pointers?
I'm also not sure if using list.len()
is the right "length", so I also tried
const listItems = new Uint8Array(memory.buffer, listItemsPtr, list.buffer_len());
which logs the JavaScript equivalent of [0; 48]
. I have no idea what this means or why I'm getting all zeros.
Is every struct's total bytes, from all its fields, condensed into a single array of bytes? So, the size of a Vec<Diagnostic>
would be:
the size of a Vec + the sum of a Diagnostic's fields' sizes (their types + their data)?
How do you get an element in listItems
at each index, and then how do you get the data in each field without creating a getter in Rust for every field or part of a field you want to read?