Rust WebAssembly 绑定输入类型(基于 Serde)
前言
单位有个项目要共享前后端检查策略后端用的正好也是 Rust,但是 Rust 默认的 wasm-bindgen
包中提供的转换操作非常少,像 Vec<T> <=> Array<T>
或者 Box<dyn T> <=> T
的转换就不行了。但是可以从 Typescript 构建这些类型,然后通过序列化的好朋友的 serde
把他们转换回 Rust 来问题。
项目结构
Cargo.toml
src
│ algorithms.rs 共享的算法
│ lib.rs
│ models.rs 共享的数据结构
└─wasm
mod.rs
model_bridge.rs 共享数据结构与自定接口的转换
typescript_custom_types.rs Typescript 中的自定接口
utils.rs
Cargo.toml
中添加新依赖
[dependencies]
# serde 是各种项目必备的,这个是 Rust 各种序列化的基础
serde = { version = "1.0", features = ["derive"] }
# Wasm 绑定工具,需要 Serde 转换特性
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
在 typescript_custom_types.rs
中编写自定义的数据结构
use wasm_bindgen::prelude::*;
#[wasm_bindgen(typescript_custom_section)]
pub const IMODEL_TSTEXT: &'static str = r#"
interface IModel {
id: string,
name: string,
}
"#;
编写模型结构体和算法
//! models.rs
use serde::*;
/// 模型类
/// 这里一定要用 `Serialize`, `Deserialize` 转换类型的关键
/// 用 camelCase 则是让 Typescript 和 rust 的命名系统相互转换
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Model {
pub id: String,
pub name: String,
}
算法没有什么好讲的,写很日常的一个方法就可以
model_bridge.rs
编写转换或者绑定方法
use crate::models::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
/// 绑定 Typescript 中刚才定义的 IModel
#[wasm_bindgen(typescript_type = "IModel")]
pub type IModel;
}
/// 转换
impl From<IModel> for Model {
fn from(f: IModel) -> Model {
model.into_serde().unwrap()
}
}
/// 入口
/// `js_name` 是方法在 Typescript 里显示的名称
#[wasm_bindgen(js_name = "testModel")]
pub fn test_model(model: IModel) -> bool {
let m: Model = model.into_serde().unwrap();
crate::algorithms::test_model(m)
}
检查生成的文件
/*
* 手动定义的接口
*/
interface IModel {
id: string,
name: string,
}
/*
* 自动生成的绑定
*/
export function testModel(model: IModel): boolean;