Rust 型別轉換
先前我們大多看到的是當值進入 Rust 時,型別轉換的簡化版本。在這裡,我們將更深入地探討這是如何實現的。轉換值有兩個類別的 trait,一個是將值從 Rust 轉換為 JS 的 trait,另一個是反向轉換的 trait。
從 Rust 到 JS
首先,讓我們看看從 Rust 到 JS 的轉換
# #![allow(unused_variables)] #fn main() { pub trait IntoWasmAbi: WasmDescribe { type Abi: WasmAbi; fn into_abi(self) -> Self::Abi; } #}
就是這樣!這實際上是目前將 Rust 值轉換為 JS 值所需的唯一 trait。這裡有幾點需要注意
-
我們將在本節稍後介紹
WasmDescribe
。 -
關聯型別
Abi
是我們實際要傳遞給 JS 的原始資料型別。WasmAbi
限制條件是針對像是u32
和f64
這類的原始型別實作的,這些原始型別可以直接表示為 WebAssembly 值,以及其他一些型別,例如WasmSlice
# #![allow(unused_variables)] #fn main() { pub struct WasmSlice { pub ptr: u32, pub len: u32, } #}
這個結構體 (這是字串之類的東西在 FFI 中表示的方式) 並不是 WebAssembly 原始型別,因此無法直接對應到 WebAssembly 參數/傳回值。這就是為什麼
WasmAbi
允許型別指定如何將其拆分為多個 WebAssembly 參數# #![allow(unused_variables)] #fn main() { impl WasmAbi for WasmSlice { fn split(self) -> (u32, u32, (), ()) { (self.ptr, self.len, (), ()) } // some other details to specify return type of `split`, go in the other direction } #}
這表示
WasmSlice
會被拆分為兩個u32
參數。結尾處的額外單元型別是因為 Rust 不允許我們針對變長元組使WasmAbi
泛型化,所以我們只取 4 個元素的元組。單元型別仍然最終被傳遞給/從 JS 傳遞,但 C ABI 完全忽略它們,並且不會產生任何引數。由於我們無法傳回多個值,當傳回
WasmSlice
時,我們改為將兩個u32
放入#[repr(C)]
結構體並傳回它。 -
最後,我們有
into_abi
函式,傳回Abi
關聯型別,這將實際傳遞給 JS。
這個 trait 是針對所有可以轉換為 JS 的型別實作的,並且在程式碼產生期間無條件使用。例如,您經常會看到 IntoWasmAbi for Foo
,也會看到 IntoWasmAbi for &'a Foo
。
IntoWasmAbi
trait 用於兩個位置。首先,它用於將 Rust 匯出函式的傳回值轉換為 JS。其次,它用於轉換匯入到 Rust 的 JS 函式的 Rust 引數。
從 JS 到 Rust
不幸的是,與上述相反的方向 (從 JS 到 Rust) 會稍微複雜一些。這裡我們有三個 trait
# #![allow(unused_variables)] #fn main() { pub trait FromWasmAbi: WasmDescribe { type Abi: WasmAbi; unsafe fn from_abi(js: Self::Abi) -> Self; } pub trait RefFromWasmAbi: WasmDescribe { type Abi: WasmAbi; type Anchor: Deref<Target=Self>; unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor; } pub trait RefMutFromWasmAbi: WasmDescribe { type Abi: WasmAbi; type Anchor: DerefMut<Target=Self>; unsafe fn ref_mut_from_abi(js: Self::Abi) -> Self::Anchor; } #}
FromWasmAbi
相對簡單,基本上與 IntoWasmAbi
相反。它接受 ABI 引數 (通常與 IntoWasmAbi::Abi
相同) 來產生 Self
的實例。這個 trait 主要針對沒有內部生命週期或參考的型別實作。
這裡的後兩個 trait 大致相同,它們的目的是產生參考 (共享和可變參考)。它們看起來幾乎與 FromWasmAbi
相同,除了它們傳回實作了 Deref
trait 而非 Self
的 Anchor
型別。
Ref*
trait 允許在函式中使用引數 (它們是參考,而不是裸型別),例如 &str
、&JsValue
或 &[u8]
。這裡需要 Anchor
來確保生命週期不會持續超過一個函式呼叫並且保持匿名。
From*
系列的 trait 用於將 Rust 導出函數中的 Rust 參數轉換為 JavaScript 參數。它們也用於導入到 Rust 的 JavaScript 函數中的回傳值。