從 JS 匯入函式
既然我們已經將一些豐富的功能匯出到 JS,現在也是時候匯入一些功能了!這裡的目標基本上是在 Rust 中實作 JS 的 `import` 語句,並包含花俏的類型。
首先,假設我們反轉上面的函式,並想要在 JS 中產生問候語,但從 Rust 中呼叫它。例如,我們可能會有
# #![allow(unused_variables)] #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` 函式會修飾該匯入。
這裡正在進行一些複雜的 ABI 處理,所以我們也來看看產生的 Rust。與之前一樣,這與實際產生的內容相比已經簡化了。
# #![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) ) } } #}
在這裡,我們可以看到 `greet` 函式已經產生,但它基本上只是圍繞我們正在呼叫的 `__wbg_f_greet` 函式的 shim。引數的 ptr/len 配對作為兩個引數傳遞,對於傳回值,我們間接地接收一個值(長度),同時直接接收傳回的指標。