Rust插件库extism-convert的使用:Extism通用数据转换与跨语言兼容性工具
extism-convert
extism-convert crate 被 Rust SDK 和 Rust PDK 使用,为编码和解码可传递给 Extism 函数调用的值提供共享接口。
它还提供了一组类型(Json、Msgpack、Protobuf),可用于指定 serde 编码。这些类似于 axum extractors - 它们实现为具有单个字段的元组结构体,该字段旨在使用模式匹配提取。
文档
请参阅 extism-convert 文档以获取深入的文档。
安装
在项目目录中运行以下 Cargo 命令:
cargo add extism-convert
或者将以下行添加到你的 Cargo.toml:
extism-convert = "1.12.0"
完整示例
以下是一个使用 extism-convert 进行数据转换的完整示例:
use extism_convert::{Json, ToBytes};
use serde::{Serialize, Deserialize};
// 定义一个可序列化的结构体
#[derive(Serialize, Deserialize)]
struct Person {
name: String,
age: u32,
}
fn main() {
// 创建 Person 实例
let person = Person {
name: "Alice".to_string(),
age: 30,
};
// 将 Person 转换为 JSON 字节
let json_bytes: Vec<u8> = Json(person).to_bytes().unwrap();
println!("JSON bytes: {:?}", json_bytes);
// 从字节反序列化
let decoded_person: Json<Person> = Json::from_bytes(&json_bytes).unwrap();
println!("Decoded person: {:?} {}", decoded_person.0.name, decoded_person.0.age);
}
扩展示例
以下是使用 Msgpack 格式的完整示例:
use extism_convert::{Msgpack, ToBytes};
use serde::{Serialize, Deserialize};
// 定义一个可序列化的结构体
#[derive(Serialize, Deserialize, Debug)]
struct Product {
id: u64,
name: String,
price: f64,
}
fn main() {
// 创建 Product 实例
let product = Product {
id: 12345,
name: "Rust Programming Book".to_string(),
price: 39.99,
};
// 将 Product 转换为 Msgpack 字节
let msgpack_bytes: Vec<u8> = Msgpack(product).to_bytes().unwrap();
println!("Msgpack bytes: {:?}", msgpack_bytes);
// 从字节反序列化
let decoded_product: Msgpack<Product> = Msgpack::from_bytes(&msgpack_bytes).unwrap();
println!("Decoded product: {:?}", decoded_product.0);
}
这个示例展示了:
- 定义一个可序列化的结构体
Product
- 使用
Msgpack
包装器将结构体转换为字节 - 从字节反序列化回结构体
extism-convert 还支持 Protobuf 编码格式,使用方法类似。
1 回复
Rust插件库extism-convert的使用指南
概述
extism-convert是一个用于Extism插件系统的Rust库,专注于提供通用数据转换功能和跨语言兼容性支持。它简化了在Rust插件与不同语言宿主之间传递数据的过程,是构建跨语言插件系统的理想工具。
主要特性
- 提供Rust与Extism主机之间的双向数据转换
- 支持多种数据类型的高效序列化/反序列化
- 简化跨语言边界的数据传递
- 与Extism插件系统无缝集成
安装方法
在Cargo.toml中添加依赖:
[dependencies]
extism-convert = "0.1"
extism-pdk = "1.0"
完整示例代码
下面是一个完整的extism-convert使用示例,展示如何创建一个完整的Extism插件:
// 导入所需库
use extism_pdk::*;
use extism_convert::{FromExtism, ToExtism};
use serde::{Serialize, Deserialize};
// 定义输入数据结构
#[derive(FromExtism, ToExtism, Serialize, Deserialize)]
struct PluginInput {
command: String,
parameters: Vec<String>,
config: std::collections::HashMap<String, String>,
}
// 定义输出数据结构
#[derive(FromExtism, ToExtism, Serialize, Deserialize)]
struct PluginOutput {
success: bool,
result: String,
execution_time: f64,
}
// 主插件函数
#[plugin_fn]
pub fn handle_request(input: Vec<u8>) -> FnResult<Vec<u8>> {
// 1. 反序列化输入数据
let input_data = PluginInput::from_extism(&input)?;
// 2. 处理输入数据
let start_time = std::time::Instant::now();
let result = process_command(&input_data);
let elapsed = start_time.elapsed().as_secs_f64();
// 3. 准备输出数据
let output = PluginOutput {
success: result.is_ok(),
result: result.unwrap_or_else(|e| e.to_string()),
execution_time: elapsed,
};
// 4. 序列化输出数据
Ok(output.to_extism()?)
}
// 命令处理函数
fn process_command(input: &PluginInput) -> Result<String, Box<dyn std::error::Error>> {
match input.command.as_str() {
"greet" => {
let name = input.parameters.get(0).unwrap_or(&"world".to_string());
Ok(format!("Hello, {}!", name))
},
"calculate" => {
let nums: Vec<i32> = input.parameters
.iter()
.filter_map(|s| s.parse().ok())
.collect();
let sum: i32 = nums.iter().sum();
Ok(format!("Sum: {}", sum))
},
_ => Err("Unknown command".into()),
}
}
示例说明
-
数据结构定义:
- 定义了
PluginInput
和PluginOutput
两个结构体,都派生自FromExtism
和ToExtism
trait - 添加了
Serialize
和Deserialize
派生以支持JSON序列化
- 定义了
-
插件主函数:
- 接收二进制输入数据
- 使用
from_extism
反序列化为Rust结构体 - 处理业务逻辑
- 使用
to_extism
序列化结果并返回
-
性能监控:
- 记录了命令执行时间
- 包含在返回给宿主的数据中
-
错误处理:
- 使用Rust标准的Result类型处理错误
- 错误信息包含在输出结构中
跨语言兼容性建议
- 使用标准数据类型和结构
- 为复杂结构实现清晰的序列化/反序列化逻辑
- 添加适当的错误处理机制
- 考虑添加版本兼容性检查
性能优化提示
- 对于大型数据,考虑流式处理
- 重用缓冲区减少内存分配
- 对性能关键路径进行基准测试