How to expose a function to Javascript that takes a Uint32Array and returns a Uint32Array?
Hello, sorry for the noob question but I am extremely new to WASM and this is the final step I need to get my code working, and I can't quite figure it out.
For my website I am looking to offload a very intensive computation to WASM, and I thought Rust would be a good fit for this. Basically, I would like to send a matrix from Javascript to my WASM library and have it process it and then return a new matrix.
I have already written all the Rust code that computes the matrix (in Rust I am using a Vec
Unfortunately, I am getting some errors. First I tried doing this:
#[wasm_bindgen]
pub fn calculate_matrix(pixels: &mut Vec<usize>) -> Vec<usize> {
// elided
}
But that was giving me this compiler error:
error[E0277]: the trait bound `Vec<usize>: RefMutFromWasmAbi` is not satisfied
--> src\lib.rs:23:1
|
23 | #[wasm_bindgen]
| ^^^^^^^^^^^^^^^ the trait `RefMutFromWasmAbi` is not implemented for `Vec<usize>`
I thought maybe it was because it was only supported for u32 and not usize and that it's not allowed to be a mutable reference, so I had my function take a Vec<u32> instead and just clone the vec in the function back to usize, and that kind of worked, except now I'm getting a runtime error.
When I run wasm-pack build I get around 1000 pages of compiled WASM text output, and I have figured out that it is due to me trying to return a Vec<u32 from the function. If I remove the return value then it compiles successfully. For some reason it is not letting me return a Vec<u32>, but I'm not sure why. I thought that it would allow this but Javascript would just interpret it as a Uint32Array.
I was looking through the runtime compile logs and found these snippets:
Fatal: error in validating input
Error: failed to execute `wasm-opt`: exited with exit code: 1
full command: "C:\\Users\\Admin\\AppData\\Local\\.wasm-pack\\wasm-opt-171374efd61df962\\wasm-opt.exe" "C:\\Users\\Admin\\Desktop\\wasm-rust\\pkg\\wasm_rust_bg.wasm" "-o" "C:\\Users\\Admin\\Desktop\\wasm-rust\\pkg\\wasm_rust_bg.wasm-opt.wasm" "-O"
To disable `wasm-opt`, add `wasm-opt = false` to your package metadata in your `Cargo.toml`.
Hmm, okay so I think what I might need to do is have the function take a &[u32] and return a Box<[u32]>, but that is still resulting in the same error in validating input runtime error. Even stranger, I found this page:
https://rustwasm.github.io/wasm-bindgen/reference/types/boxed-number-slices.html
And one of the code snippets gives me the same error:
#[wasm_bindgen]
pub fn return_boxed_number_slice() -> Box<[u32]> {
(0..42).collect::<Vec<u32>>().into_boxed_slice()
}
Also results in me getting the same runtime error. Is it possible this used to be allowed but is now different and the docs haven't been updated? Or maybe I'm doing something else wrong?
Ah, it appears that was an unrelated bug (from here: https://github.com/rustwasm/wasm-pack/issues/886#issuecomment-667669802) and it has now compiled. Nice, progress!
You should be able to return Vec<u32> from a function as well as take &[u32] as well as an argument. Additionally you can take/return js_sys::Uint32Array which should work to. Have your issues been fixed at this point or are you still loooking for help?
I am a newbie too and I encountered this problem, I wrote a dummy function to test but it did not work:
// Rust
#[wasm_bindgen]
pub fn my_dummy_function(
num_samples: u32,
) -> Vec<u32>
{
let my_array: Vec<u32> = vec![12; num_samples as usize];
//Clone::clone(&my_array)
my_array
}
In the frontend the rust module is loaded like this:
import('../wasm-test-pack/pkg/myDummyPackage_bg.wasm').then((response) => {
this.myFirstResult = response.add_one(1);
console.log("Test dummy add: " + this.myFirstResult); // Works fine !! returns 2
console.log("Test dummy vector: " + response.my_dummy_function(1,1)); // Only works if I take two arguments
});
The strange thing is after compiling the rust-wasm pack, the myDummyPackage.d.ts has the following exports:
Note that the function add_one is correct and it's working while my_dummy_function takes two numbers when in rust it takes only one input.
export const memory: WebAssembly.Memory;
export function my_dummy_function(a: number, b: number): void;
export function add_one(a: number): number;
...
I am on ubuntu 22.04, rustc 1.71.0, I would really appreciate some help here :pray:
That's happening because you're importing the wrong file: you should be importing pkg/myDummyPackage.js, not pkg/myDummyPackage_bg.wasm.
pkg/myDummyPackage_bg.wasm is the underlying WebAssembly that gets created by rustc, and pkg/myDummyPackage.js is a JS wrapper for it created by wasm-bindgen. The reason that it needs to exist is that WebAssembly can only directly pass numbers to and from JS, which is what you're seeing in those TypeScript declarations; the JS wrapper then converts them to JS values (in this case, a Uint32Array).
Actually, when using the ".js" file I was not even able to get the result from the function add_one(a: number): number;, I also have not specified, but I use the angular framework. I use similar approach as this repo. When I use import and specify the ".js" file, this is what I get:
When I import using the "wasm" file:
I am actually not sure how much of the problem angular-related, also if there is another way to make the import using js that would fix the problem I would appreciate to know how :-)
The repo you linked instantiates the Wasm module by itself calling WebAssembly.instantiate(), if you gave it the JS file then the error message isn't surprising. The generated JS shim by wasm-bindgen exports a default function, which you should use to initialize the Wasm module.
Unfortunately I know nothing about Angular, but it would certainly help to see the code again you changed to get to where you are now.