Rust 类型转换

之前,我们看到的大多是值进入 Rust 时类型转换的简化版本。在这里,我们将更深入地了解它是如何实现的。转换值有两种特征类别,一种是将值从 Rust 转换为 JS 的特征,另一种是从 JS 转换为 Rust 的特征。

从 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 为诸如 u32f64 之类的原始类型实现,这些类型可以直接表示为 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。其次,它用于将导入到 Rust 的 JS 函数的 Rust 参数进行转换。

从 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 相同,只是它们返回一个实现 Deref 特征而不是 SelfAnchor 类型。

Ref* 特征允许函数中的参数是引用而不是裸类型,例如 &str&JsValue&[u8]。此处需要 Anchor 来确保生命周期不会持续超过一个函数调用,并且保持匿名。

From* 特征系列用于将 Rust 导出函数中的 Rust 参数转换为 JS。它们也用于导入到 Rust 的 JS 函数中的返回值。