Importing a function from JS
Now that we've exported some rich functionality to JS it's also time to import
some! The goal here is to basically implement JS import
statements in Rust,
with fancy types and all.
First up, let's say we invert the function above and instead want to generate greetings in JS but call it from Rust. We might have, for example:
# #![allow(unused_variables)] #fn main() { #[wasm_bindgen(module = "./greet")] extern "C" { fn greet(a: &str) -> String; } fn other_code() { let greeting = greet("foo"); // ... } #}
The basic idea of imports is the same as exports in that we'll have shims in both JS and Rust doing the necessary translation. Let's first see the JS shim in action:
import * as wasm from './foo_bg';
import { greet } from './greet';
// ...
export function __wbg_f_greet(ptr0, len0, wasmretptr) {
const [retptr, retlen] = passStringToWasm(greet(getStringFromWasm(ptr0, len0)));
(new Uint32Array(wasm.memory.buffer))[wasmretptr / 4] = retlen;
return retptr;
}
The getStringFromWasm
and passStringToWasm
are the same as we saw before,
and like with __wbindgen_object_drop_ref
far above we've got this weird export
from our module now! The __wbg_f_greet
function is what's generated by
wasm-bindgen
to actually get imported in the foo.wasm
module.
The generated foo.js
we see imports from the ./greet
module with the greet
name (was the function import in Rust said) and then the __wbg_f_greet
function is shimming that import.
There's some tricky ABI business going on here so let's take a look at the generated Rust as well. Like before this is simplified from what's actually generated.
# #![allow(unused_variables)] #fn main() { extern "C" fn greet(a: &str) -> String { extern "C" { fn __wbg_f_greet(a_ptr: *const u8, a_len: usize, ret_len: *mut usize) -> *mut u8; } unsafe { let a_ptr = a.as_ptr(); let a_len = a.len(); let mut __ret_strlen = 0; let mut __ret_strlen_ptr = &mut __ret_strlen as *mut usize; let _ret = __wbg_f_greet(a_ptr, a_len, __ret_strlen_ptr); String::from_utf8_unchecked( Vec::from_raw_parts(_ret, __ret_strlen, __ret_strlen) ) } } #}
Here we can see that the greet
function was generated but it's largely just a
shim around the __wbg_f_greet
function that we're calling. The ptr/len pair
for the argument is passed as two arguments and for the return value we're
receiving one value (the length) indirectly while directly receiving the
returned pointer.