Rust 型別轉換
先前我們看到的主要是當值進入 Rust 時,型別轉換的簡略版本。在這裡,我們將深入探討這是如何實作的。轉換值的特性有兩種類別,一類是將值從 Rust 轉換為 JS 的特性,另一類是反向的特性。
從 Rust 到 JS
首先,讓我們看看從 Rust 到 JS 的轉換
#![allow(unused)] fn main() { pub trait IntoWasmAbi: WasmDescribe { type Abi: WasmAbi; fn into_abi(self) -> Self::Abi; } }
就是這樣!這實際上是目前將 Rust 值轉換為 JS 值所需的唯一特性。這裡有幾點需要說明
-
我們將在本節稍後介紹
WasmDescribe
。 -
關聯型別
Abi
是我們實際想要傳遞給 JS 的原始資料的型別。對於像u32
和f64
這樣的基本型別,以及其他一些型別,例如WasmSlice
,已經實作了界限WasmAbi
,這些型別可以直接表示為 WebAssembly 值。#![allow(unused)] fn main() { pub struct WasmSlice { pub ptr: u32, pub len: u32, } }
這個結構體是像字串之類的東西在 FFI 中如何表示的,它不是 WebAssembly 基本型別,因此無法直接對應到 WebAssembly 參數/傳回值。這就是為什麼
WasmAbi
讓型別指定如何將它們分成多個 WebAssembly 參數的原因#![allow(unused)] 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
函數,它傳回實際將傳遞給 JS 的Abi
關聯型別。
此特性針對所有可以轉換為 JS 的型別實作,並且在程式碼產生期間無條件使用。例如,您經常會看到 IntoWasmAbi for Foo
,但也看到 IntoWasmAbi for &'a Foo
。
IntoWasmAbi
特性在兩個位置使用。首先,它用於將 Rust 匯出函式的傳回值轉換為 JS。其次,它用於轉換匯入 Rust 的 JS 函式的 Rust 引數。
從 JS 到 Rust
不幸的是,與上面相反的方向,從 JS 到 Rust 的轉換稍微複雜一些。這裡我們有三個特性
#![allow(unused)] 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
的實例。此特性主要針對 _沒有_ 內部生命週期或為參考的型別實作。
這裡的後兩個特性大多相同,旨在產生參考 (共享參考和可變參考)。它們看起來與 FromWasmAbi
幾乎相同,只是它們傳回一個實作 Deref
特性而不是 Self
的 Anchor
型別。
Ref*
特性允許在函式中包含參考而不是裸型別的引數,例如 &str
、&JsValue
或 &[u8]
。此處需要 Anchor
以確保生命週期不會超過一個函式呼叫並且保持匿名。
From*
系列特性用於將 Rust 匯出函式中的 Rust 引數轉換為 JS。它們也用於匯入 Rust 的 JS 函式的傳回值。