Rust插件库Cactus的使用:高效、灵活的插件系统扩展,提升Rust应用模块化开发能力

Rust插件库Cactus的使用:高效、灵活的插件系统扩展,提升Rust应用模块化开发能力

Cactus库提供了一个不可变的仙人掌栈(也称为意大利面条栈或父指针树)。仙人掌栈是一个(可能为空的)节点,带有一个(可能为空的)指向父节点的指针。任何给定节点都有一个返回根节点的唯一路径。与其可变地更新栈,不如创建和获取对不可变节点的访问(当节点变得不可达时,其内存会自动回收)。

基本使用示例

use cactus::Cactus;
let c = Cactus::new();
assert!(c.is_empty());
let c2 = c.child(1);
assert_eq!(c2.len(), 1);
assert_eq!(*c2.val().unwrap(), 1);
let c3 = c2.parent().unwrap();
assert!(c3.is_empty());

创建多个子栈示例

use cactus::Cactus;
let c = Cactus::new().child(1);
let c2 = c.child(2);
let c3 = c.child(3);
assert!(c2 != c3);
assert_eq!(c2.vals().cloned().collect::<Vec<_>>(), [2, 1]);
assert_eq!(c3.vals().cloned().collect::<Vec<_>>(), [3, 1]);

完整示例代码

下面是一个更完整的示例,展示了如何使用Cactus库来构建一个简单的插件系统:

use cactus::Cactus;

// 定义插件特征
trait Plugin {
    fn name(&self) -> &str;
    fn execute(&self);
}

// 实现一个具体插件
struct GreetPlugin;
impl Plugin for GreetPlugin {
    fn name(&self) -> &str {
        "greet"
    }
    
    fn execute(&self) {
        println!("Hello from GreetPlugin!");
    }
}

// 实现另一个插件
struct LogPlugin;
impl Plugin for LogPlugin {
    fn name(&self) &str {
        "log"
    }
    
    fn execute(&self) {
        println!("Logging from LogPlugin");
    }
}

fn main() {
    // 创建空的插件栈
    let plugin_stack = Cactus::new();
    
    // 添加插件
    let with_greet = plugin_stack.child(GreetPlugin);
    let with_log = with_greet.child(LogPlugin);
    
    // 遍历并执行所有插件
    for plugin in with_log.vals() {
        plugin.execute();
    }
    
    // 输出:
    // Logging from LogPlugin
    // Hello from GreetPlugin!
}

更复杂的插件系统示例

use cactus::Cactus;
use std::any::{Any, TypeId};

// 定义插件管理器和特征
struct PluginManager {
    plugins: Cactus<Box<dyn Any>>,
}

impl PluginManager {
    fn new() -> Self {
        Self {
            plugins: Cactus::new(),
        }
    }
    
    fn add_plugin<T: 'static>(&self, plugin: T) -> Self {
        Self {
            plugins: self.plugins.child(Box::new(plugin)),
        }
    }
    
    fn get_plugin<T: 'static>(&self) -> Option<&T> {
        for plugin in self.plugins.vals() {
            if plugin.is::<T>() {
                return plugin.downcast_ref::<T>();
            }
        }
        None
    }
}

// 定义几个插件类型
struct DatabasePlugin {
    connection: String,
}

struct AuthPlugin {
    token: String,
}

fn main() {
    let manager = PluginManager::new()
        .add_plugin(DatabasePlugin {
            connection: "localhost".to_string(),
        })
        .add_plugin(AuthPlugin {
            token: "secret".to_string(),
        });
    
    // 获取并使用插件
    if let Some(db) = manager.get_plugin::<DatabasePlugin>() {
        println!("Database connection: {}", db.connection);
    }
    
    if let Some(auth) = manager.get_plugin::<AuthPlugin>() {
        println!("Auth token: {}", auth.token);
    }
}

这些示例展示了如何使用Cactus库来构建灵活、可扩展的插件系统,使Rust应用具有更好的模块化开发能力。通过不可变的数据结构和父子关系,可以安全地管理插件生命周期和依赖关系。

完整示例Demo

基于上述内容,下面是一个更完整的Cactus插件系统实现示例,展示了如何在实际项目中使用:

use cactus::Cactus;
use std::any::{Any, TypeId};

// 定义插件特征
trait Plugin: Any {
    fn name(&self) -> &str;
    fn init(&self);
    fn execute(&self, context: &mut PluginContext);
}

// 插件上下文
struct PluginContext {
    data: String,
}

// 具体插件实现 - 日志插件
struct LoggerPlugin {
    log_level: String,
}

impl Plugin for LoggerPlugin {
    fn name(&self) -> &str {
        "logger"
    }

    fn init(&self) {
        println!("Initializing LoggerPlugin with level: {}", self.log_level);
    }

    fn execute(&self, context: &mut PluginContext) {
        println!("[{}] Processing: {}", self.log_level, context.data);
        context.data = context.data.to_uppercase();
    }
}

// 具体插件实现 - 验证插件
struct ValidationPlugin;

impl Plugin for ValidationPlugin {
    fn name(&self) -> &str {
        "validator"
    }

    fn init(&self) {
        println!("Initializing ValidationPlugin");
    }

    fn execute(&self, context: &mut PluginContext) {
        if context.data.is_empty() {
            println!("Validation error: empty input");
        }
    }
}

// 插件管理器
struct PluginSystem {
    plugins: Cactus<Box<dyn Plugin>>,
}

impl PluginSystem {
    fn new() -> Self {
        Self {
            plugins: Cactus::new(),
        }
    }

    fn add_plugin<P: Plugin + 'static>(mut self, plugin: P) -> Self {
        println!("Adding plugin: {}", plugin.name());
        plugin.init();
        Self {
            plugins: self.plugins.child(Box::new(plugin)),
        }
    }

    fn execute_all(&self, mut context: PluginContext) -> PluginContext {
        for plugin in self.plugins.vals() {
            plugin.execute(&mut context);
        }
        context
    }
}

fn main() {
    // 创建插件系统并添加插件
    let system = PluginSystem::new()
        .add_plugin(LoggerPlugin {
            log_level: "INFO".to_string(),
        })
        .add_plugin(ValidationPlugin);

    // 创建执行上下文
    let mut context = PluginContext {
        data: "hello world".to_string(),
    };

    // 执行所有插件
    context = system.execute_all(context);
    println!("Final result: {}", context.data);

    // 输出:
    // Adding plugin: logger
    // Initializing LoggerPlugin with level: INFO
    // Adding plugin: validator
    // Initializing ValidationPlugin
    // [INFO] Processing: hello world
    // Final result: HELLO WORLD
}

1 回复

Rust插件库Cactus使用指南

Cactus简介

Cactus是一个高效、灵活的Rust插件系统库,旨在提升Rust应用的模块化开发能力。它提供了轻量级的插件架构,允许开发者动态加载和卸载功能模块,而无需重新编译主应用程序。

主要特性

  • 动态加载:支持运行时加载和卸载插件
  • 类型安全:利用Rust的类型系统保证插件接口安全
  • 跨平台:支持Windows、Linux和macOS
  • 低开销:设计注重性能,插件调用开销小
  • 灵活扩展:易于集成到现有项目中

安装方法

在Cargo.toml中添加依赖:

[dependencies]
cactus = "0.3"

完整示例demo

1. 创建接口库 (plugins-interface)

// plugins-interface/src/lib.rs
use cactus::Plugin;

#[derive(Plugin)]
pub trait Greeter {
    fn greet(&self, name: &str) -> String;
}

#[derive(Plugin)]
pub trait Calculator {
    fn add(&self, a: i32, b: i32) -> i32;
    fn multiply(&self, a: i32, b: i32) -> i32;
}

2. 实现插件 (plugin-hello)

// plugin-hello/src/lib.rs
use plugins_interface::{Greeter, Calculator};

#[derive(Default)]
pub struct HelloPlugin;

impl Greeter for HelloPlugin {
    fn greet(&self, name: &str) -> String {
        format!("Hello, {}! Welcome to Cactus plugin system.", name)
    }
}

impl Calculator for HelloPlugin {
    fn add(&self, a: i32, b: i32) -> i32 {
        a + b
    }
    
    fn multiply(&self, a: i32, b: i32) -> i32 {
        a * b
    }
}

// 必须导出插件创建函数
#[no_mangle]
pub extern "C" fn _plugin_create() -> *mut () {
    let plugin = Box::new(HelloPlugin::default());
    Box::into_raw(plugin) as *mut _
}

3. 主程序 (my-app)

// my-app/src/main.rs
use cactus::{PluginLoader, PluginManager};
use plugins_interface::{Greeter, Calculator};

fn main() {
    // 1. 使用PluginLoader加载单个插件
    println!("=== 使用PluginLoader ===");
    let mut loader = PluginLoader::new();
    
    // 根据平台加载插件
    #[cfg(target_os = "linux")]
    let plugin_path = "./target/debug/libplugin_hello.so";
    
    #[cfg(target_os = "windows")]
    let plugin_path = "./target/debug/plugin_hello.dll";
    
    #[cfg(target_os = "macos")]
    let plugin_path = "./target/debug/libplugin_hello.dylib";
    
    loader.load(plugin_path).expect("加载插件失败");
    
    // 使用Greeter功能
    let greeter = loader.get::<dyn Greeter>().expect("获取Greeter失败");
    println!("{}", greeter.greet("Developer"));
    
    // 使用Calculator功能
    let calculator = loader.get::<dyn Calculator>().expect("获取Calculator失败");
    println!("5 + 3 = {}", calculator.add(5, 3));
    println!("5 * 3 = {}", calculator.multiply(5, 3));
    
    loader.unload().expect("卸载插件失败");
    
    // 2. 使用PluginManager管理多个插件
    println!("\n=== 使用PluginManager ===");
    let mut manager = PluginManager::new();
    
    // 加载多个插件
    manager.load_all(vec![plugin_path]).expect("加载插件失败");
    
    // 获取并使用插件
    if let Some(greeter) = manager.get::<dyn Greeter>("hello") {
        println!("{}", greeter.greet("Manager User"));
    }
    
    if let Some(calc) = manager.get::<dyn Calculator>("hello") {
        println!("10 + 20 = {}", calc.add(10, 20));
    }
    
    // 卸载所有插件
    manager.unload_all().expect("卸载插件失败");
}

4. 项目配置文件

接口库Cargo.toml

[package]
name = "plugins-interface"
version = "0.1.0"
edition = "2021"

[dependencies]
cactus = "0.3"

插件库Cargo.toml

[package]
name = "plugin-hello"
version = "0.1.0"
edition = "2021"
crate-type = ["cdylib"]

[dependencies]
plugins-interface = { path = "../interface" }
cactus = "0.3"

主程序Cargo.toml

[package]
name = "my-app"
version = "0.1.0"
edition = "2021"

[dependencies]
cactus = "0.3"
plugins-interface = { path = "./plugins/interface" }

构建和运行步骤

  1. 先构建接口库:
cd plugins/interface
cargo build
  1. 构建插件库:
cd ../hello
cargo build
  1. 运行主程序:
cd ../../my-app
cargo run

注意事项

  1. 插件和主程序必须使用相同版本的Rust编译器
  2. 在Windows上需要注意动态链接库的依赖关系
  3. 插件卸载后不应再使用其提供的任何对象
  4. 跨插件通信应通过主程序进行
回到顶部