Importing a function from JS - The `wasm-bindgen` Guide

# 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)]
    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)]
    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.