Rust 类型转换
之前我们主要看到了值进入 Rust 时类型转换的简化版本。在这里,我们将更深入地了解其实现方式。有两种类型的特征用于转换值,一种用于将值从 Rust 转换为 JS,另一种用于相反方向的转换。
从 Rust 到 JS
首先,让我们看看从 Rust 到 JS 的转换
# #![allow(unused_variables)] #fn main() { pub trait IntoWasmAbi: WasmDescribe { type Abi: WasmAbi; fn into_abi(self) -> Self::Abi; } #}
就是这样!这实际上是目前将 Rust 值转换为 JS 值所需的唯一特征。这里有几点需要注意
-
我们将在本节后面介绍
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
函数,它返回将实际传递给 JS 的关联类型Abi
。
这个特征是为所有可以转换为 JS 的类型实现的,并且在代码生成期间无条件地使用。例如,你经常会看到 IntoWasmAbi for Foo
,但也会看到 IntoWasmAbi for &'a Foo
。
IntoWasmAbi
特征在两个地方使用。首先,它用于将 Rust 导出函数的返回值转换为 JS。其次,它用于将 JS 函数导入 Rust 的 Rust 参数转换为 JS。
从 JS 到 Rust
不幸的是,与上述相反的方向,从 JS 到 Rust 的转换要复杂一些。这里我们有三个特征
# #![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
的实例。这个特征主要为那些没有内部生命周期或引用类型的类型实现。
这里后面的两个特征基本相同,用于生成引用(共享引用和可变引用)。它们看起来与 FromWasmAbi
几乎相同,只是它们返回一个 Anchor
类型,该类型实现了 Deref
特征而不是 Self
。
Ref*
特征允许在函数中使用引用作为参数,而不是裸类型,例如 &str
、&JsValue
或 &[u8]
。这里的 Anchor
是必需的,以确保生命周期不会持续超过一次函数调用,并且保持匿名。
From*
特征系列用于将 Rust 导出函数中的 Rust 参数转换为 JS。它们也用于 JS 函数导入 Rust 的返回值。