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);
}

这个示例展示了:

  1. 定义一个可序列化的结构体 Product
  2. 使用 Msgpack 包装器将结构体转换为字节
  3. 从字节反序列化回结构体

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()),
    }
}

示例说明

  1. 数据结构定义

    • 定义了PluginInputPluginOutput两个结构体,都派生自FromExtismToExtism trait
    • 添加了SerializeDeserialize派生以支持JSON序列化
  2. 插件主函数

    • 接收二进制输入数据
    • 使用from_extism反序列化为Rust结构体
    • 处理业务逻辑
    • 使用to_extism序列化结果并返回
  3. 性能监控

    • 记录了命令执行时间
    • 包含在返回给宿主的数据中
  4. 错误处理

    • 使用Rust标准的Result类型处理错误
    • 错误信息包含在输出结构中

跨语言兼容性建议

  1. 使用标准数据类型和结构
  2. 为复杂结构实现清晰的序列化/反序列化逻辑
  3. 添加适当的错误处理机制
  4. 考虑添加版本兼容性检查

性能优化提示

  1. 对于大型数据,考虑流式处理
  2. 重用缓冲区减少内存分配
  3. 对性能关键路径进行基准测试
回到顶部