| # 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: |
| |
| ```rust |
| #[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: |
| |
| ```js |
| 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. |
| |
| ```rust |
| 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. |