I'm working with WebAssembly right now, and wanted to be able to pass a file's bytes from JavaScript to Rust code. Currently, I've exposed the following Rust struct to JavaScript:
use js_sys::{Function, Uint8Array};
use wasm_bindgen::prelude::{wasm_bindgen, JsValue};
#[wasm_bindgen]
pub struct WasmMemBuffer {
buffer: Vec<u8>,
}
#[wasm_bindgen]
impl WasmMemBuffer {
#[wasm_bindgen(constructor)]
pub fn new(byte_length: u32, f: &Function) -> Self {
let mut buffer = vec![0; byte_length as usize];
unsafe {
let array = Uint8Array::view(&mut buffer);
f.call1(&JsValue::NULL, &JsValue::from(array))
.expect("The callback function should not throw");
}
Self { buffer }
}
}
This struct, WasmMemBuffer
, will point to a place in WebAssembly memory, meaning that I can write to it from JavaScript without any expensive copy operations.
import { WasmMemBuffer } from 'rust-crate';
const buf = new WasmMemBuffer(1000, (arr: Uint8Array) => {
for (let i = 0; i < arr.length; i++) {
arr[i] = 1.0; // Initialize the buffer with ones
}
});
This works great. However, I'd like to read a user-submitted file's contents directly into WebAssembly's linear memory, without creating an ArrayBuffer
, converting it to a Uint8Array
, and copying its values to the WasmMemBuffer
. As I understand it, FileReader
allocates a new ArrayBuffer
when calling readAsArrayBuffer
. I'd like to point it to the WasmMemBuffer
instead. Is there a way I can do this? For reference, this is the code I'm using to read the file.
// e is the onchange event from a <input type="file"> element
function readFile(e: Event) {
const target = e?.target as HTMLInputElement;
const file = target?.files?.[0];
if (!target || !file) {
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const res = e.target?.result as ArrayBuffer;
if (res) {
// Do something with res
}
};
reader.readAsArrayBuffer(file);
}