从 JS 导入函数
既然我们已经向 JS 导出了一些丰富的功能,现在也是时候导入一些了!这里的目标基本上是在 Rust 中实现 JS 的 import
语句,并带有花哨的类型等。
首先,假设我们反转上面的函数,而是想在 JS 中生成问候语,但从 Rust 中调用它。例如,我们可能有
#![allow(unused)] fn main() { #[wasm_bindgen(module = "./greet")] extern "C" { fn greet(a: &str) -> String; } fn other_code() { let greeting = greet("foo"); // ... } }
导入的基本思想与导出相同,即我们将在 JS 和 Rust 中都有 shim 来进行必要的转换。让我们首先看看 JS shim 的作用
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;
}
getStringFromWasm
和 passStringToWasm
与我们之前看到的一样,并且就像上面的 __wbindgen_object_drop_ref
一样,我们现在从我们的模块中得到了这个奇怪的导出! __wbg_f_greet
函数是 wasm-bindgen
生成的,用于实际导入到 foo.wasm
模块中。
我们看到的生成的 foo.js
从 ./greet
模块导入了 greet
名称(Rust 中的函数导入所说的),然后 __wbg_f_greet
函数正在 shim 该导入。
这里有一些棘手的 ABI 业务正在进行,所以让我们也看一下生成的 Rust。像以前一样,这是从实际生成的简化而来。
#![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) ) } } }
在这里我们可以看到 greet
函数已经生成,但它主要只是围绕我们正在调用的 __wbg_f_greet
函数的 shim。参数的 ptr/len 对作为两个参数传递,对于返回值,我们间接接收一个值(长度),同时直接接收返回的指针。