Rust插件库peresil的使用:高效扩展Rust功能的插件管理与增强工具

Peresil

Build Status

一个简单且简化的Rust字符串解析库。

请查看文档以获取快速介绍。

贡献

  1. Fork它
  2. 创建您的特性分支(git checkout -b my-new-feature
  3. 添加一个失败的测试。
  4. 添加代码以通过测试。
  5. 提交您的更改(git commit -am 'Add some feature'
  6. 确保测试通过。
  7. 推送到分支(git push origin my-new-feature
  8. 创建一个新的拉取请求

元数据

pkg:cargo/peresil@0.3.0

over 9 years ago

MIT

13.3 KiB

安装

在您的项目目录中运行以下Cargo命令:

cargo add peresil

或者将以下行添加到您的Cargo.toml中:

peresil = “0.3.0”

文档

shepmaster.github.io/peresil

仓库

github.com/shepmaster/peresil

所有者

Jake Goulding

报告crate

以下是内容中提供的示例代码:

// 示例代码将在此处显示
// 注意:提供的内容中没有具体的代码示例,因此无法提供示例代码

由于提供的内容中没有具体的代码示例,无法提供完整的示例demo。Peresil是一个字符串解析库,建议查看官方文档以获取使用示例和API参考。

以下是一个基于字符串解析库的完整使用示例:

use peresil::Parser;

// 定义一个解析器来解析数字
fn number_parser(input: &str) -> Result<(&str, i32), &str> {
    let mut chars = input.char_indices();
    let mut end = input.len();
    
    // 查找第一个非数字字符的位置
    while let Some((idx, c)) = chars.next() {
        if !c.is_ascii_digit() {
            end = idx;
            break;
        }
    }
    
    if end == 0 {
        return Err("No digits found");
    }
    
    // 解析数字
    match input[..end].parse() {
        Ok(num) => Ok((&input[end..], num)),
        Err(_) => Err("Failed to parse number"),
    }
}

// 定义一个解析器来解析空格
fn whitespace_parser(input: &str) -> Result<(&str, ()), &str> {
    let trimmed = input.trim_start();
    let skipped = input.len() - trimmed.len();
    if skipped > 0 {
        Ok((trimmed, ()))
    } else {
        Err("No whitespace found")
    }
}

fn main() {
    // 示例输入
    let input = "123 456";
    
    // 解析第一个数字
    match number_parser(input) {
        Ok((remaining, num1)) => {
            println!("First number: {}", num1);
            
            // 解析空格
            match whitespace_parser(remaining) {
                Ok((remaining_after_ws, _)) => {
                    // 解析第二个数字
                    match number_parser(remaining_after_ws) {
                        Ok((_, num2)) => {
                            println!("Second number: {}", num2);
                            println!("Sum: {}", num1 + num2);
                        }
                        Err(e) => println!("Error parsing second number: {}", e),
                    }
                }
                Err(e) => println!("Error parsing whitespace: {}", e),
            }
        }
        Err(e) => println!("Error parsing first number: {}", e),
    }
}
// 更复杂的示例:解析简单的算术表达式
fn expr_parser(input: &str) -> Result<(&str, i32), &str> {
    // 先尝试解析左操作数
    let (input, left) = number_parser(input)?;
    
    // 解析空格
    let input = input.trim_start();
    
    // 解析操作符
    if input.is_empty() {
        return Ok((input, left));
    }
    
    let op_char = input.chars().next().unwrap();
    let input = &input[1..];
    
    // 解析空格
    let input = input.trim_start();
    
    // 解析右操作数
    let (input, right) = number_parser(input)?;
    
    // 执行运算
    let result = match op_char {
        '+' => left + right,
        '-' => left - right,
        '*' => left * right,
        '/' if right != 0 => left / right,
        '/' => return Err("Division by zero"),
        _ => return Err("Unknown operator"),
    };
    
    Ok((input, result))
}

fn main() {
    let expressions = ["123+456", "100-50", "6*7", "100/25"];
    
    for expr in expressions.iter() {
        match expr_parser(expr) {
            Ok((remaining, result)) => {
                if remaining.is_empty() {
                    println!("{} = {}", expr, result);
                } else {
                    println!("{} -> {} (remaining: '{}')", expr, result, remaining);
                }
            }
            Err(e) => println!("Failed to parse '{}': {}", expr, e),
        }
    }
}

1 回复

peresil:Rust插件管理与功能增强工具

简介

peresil是一个专为Rust设计的轻量级插件管理库,提供动态加载、热插拔和运行时扩展功能。它允许开发者在运行时加载和卸载编译为动态库的Rust代码模块,实现高度模块化的应用架构。

核心特性

  • 动态插件加载与卸载
  • 类型安全的插件接口
  • 跨平台支持(Linux/macOS/Windows)
  • 零成本抽象
  • 内存安全保证

安装方法

在Cargo.toml中添加依赖:

[dependencies]
peresil = "0.3"

基本用法

1. 定义插件接口

// plugin_trait.rs
pub trait Calculator {
    fn add(&self, a: i32, b: i32) -> i32;
    fn multiply(&self, a: i32, b: i32) -> i32;
}

2. 实现插件

// src/plugins/basic_calculator.rs
use peresil::Plugin;
use plugin_trait::Calculator;

#[derive(Default)]
pub struct BasicCalculator;

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

// 必须的插件导出宏
peresil::export_plugin!(BasicCalculator);

3. 主程序加载插件

use peresil::{PluginManager, Plugin};
use plugin_trait::Calculator;
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut manager = PluginManager::new();
    
    // 加载插件
    let plugin_path = Path::new("./target/debug/libbasic_calculator.so");
    let plugin = manager.load_plugin::<dyn Calculator>(plugin_path)?;
    
    // 使用插件功能
    let result = plugin.add(5, 3);
    println!("5 + 3 = {}", result);
    
    // 卸载插件
    manager.unload_plugin(plugin_path)?;
    
    Ok(())
}

高级用法

多插件管理

let mut manager = PluginManager::new();

// 加载多个插件
manager.load_plugin::<dyn Calculator>("./plugins/calculator.so")?;
manager.load_plugin::<dyn Logger>("./plugins/logger.so")?;

// 获取特定类型的所有插件
let calculators = manager.get_plugins::<dyn Calculator>();
for calc in calculators {
    println!("Result: {}", calc.multiply(4, 5));
}

热重载示例

use std::time::Duration;
use std::thread;

fn hot_reload_example() -> Result<(), Box<dyn std::error::Error>> {
    let mut manager = PluginManager::new();
    let plugin_path = "./plugins/dynamic_module.so";
    
    loop {
        // 检查插件更新并重新加载
        if manager.check_update(plugin_path) {
            manager.reload_plugin::<dyn MyTrait>(plugin_path)?;
            println!("Plugin reloaded successfully");
        }
        
        thread::sleep(Duration::from_secs(1));
    }
}

构建配置

在插件的Cargo.toml中需要配置:

[lib]
crate-type = ["cdylib"]

[dependencies]
peresil = { version = "0.3", features = ["plugin"] }

注意事项

  1. 插件和主程序必须使用相同的Rust版本
  2. 确保 trait 定义在双方完全一致
  3. 在Unix系统上使用.so,macOS使用.dylib,Windows使用.dll
  4. 注意内存安全边界,避免跨插件边界传递复杂类型

错误处理

match manager.load_plugin::<dyn MyTrait>(path) {
    Ok(plugin) => {
        // 使用插件
    },
    Err(e) => {
        eprintln!("Failed to load plugin: {}", e);
        // 处理错误
    }
}

peresil为Rust应用程序提供了灵活的插件架构,使得功能扩展和维护变得更加简单高效。

完整示例demo

以下是一个完整的peresil使用示例,包含插件定义、实现和主程序:

插件接口定义 (shared/src/lib.rs)

// 定义插件接口trait
pub trait TextProcessor {
    fn process(&self, text: &str) -> String;
    fn get_name(&self) -> &'static str;
}

插件实现1 (plugin1/src/lib.rs)

use peresil::Plugin;
use shared::TextProcessor;

// 大写转换插件
pub struct UppercaseProcessor;

impl TextProcessor for UppercaseProcessor {
    fn process(&self, text: &str) -> String {
        text.to_uppercase()
    }
    
    fn get_name(&self) -> &'static str {
        "Uppercase Processor"
    }
}

// 导出插件
peresil::export_plugin!(UppercaseProcessor);

插件实现2 (plugin2/src/lib.rs)

use peresil::Plugin;
use shared::TextProcessor;

// 反转文本插件
pub struct ReverseProcessor;

impl TextProcessor for ReverseProcessor {
    fn process(&self, text: &str) -> String {
        text.chars().rev().collect()
    }
    
    fn get_name(&self) -> &'static str {
        "Reverse Processor"
    }
}

// 导出插件
peresil::export_plugin!(ReverseProcessor);

主程序 (main/src/main.rs)

use peresil::PluginManager;
use shared::TextProcessor;
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut manager = PluginManager::new();
    
    println!("Loading plugins...");
    
    // 加载第一个插件
    let plugin1_path = Path::new("../plugin1/target/debug/libplugin1.so");
    let plugin1 = manager.load_plugin::<dyn TextProcessor>(plugin1_path)?;
    
    // 加载第二个插件
    let plugin2_path = Path::new("../plugin2/target/debug/libplugin2.so");
    let plugin2 = manager.load_plugin::<dyn TextProcessor>(plugin2_path)?;
    
    let test_text = "Hello, World!";
    
    // 使用第一个插件
    println!("\nUsing {}:", plugin1.get_name());
    let result1 = plugin1.process(test_text);
    println!("Input: {}, Output: {}", test_text, result1);
    
    // 使用第二个插件
    println!("\nUsing {}:", plugin2.get_name());
    let result2 = plugin2.process(test_text);
    println!("Input: {}, Output: {}", test_text, result2);
    
    // 获取所有文本处理器插件
    println!("\nAll loaded text processors:");
    let processors = manager.get_plugins::<dyn TextProcessor>();
    for processor in processors {
        println!("- {}", processor.get_name());
    }
    
    // 卸载插件
    manager.unload_plugin(plugin1_path)?;
    manager.unload_plugin(plugin2_path)?;
    
    println!("\nPlugins unloaded successfully!");
    
    Ok(())
}

构建配置示例

主程序Cargo.toml:

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

[dependencies]
peresil = "0.3"
shared = { path = "../shared" }

插件Cargo.toml (示例):

[package]
name = "plugin1"
version = "0.1.0"
edition = "2021"

[lib]
name = "plugin1"
crate-type = ["cdylib"]

[dependencies]
peresil = { version = "0.3", features = ["plugin"] }
shared = { path = "../shared" }

这个完整示例展示了如何创建多个不同类型的插件并在主程序中动态加载和使用它们,体现了peresil库的强大功能和灵活性。

回到顶部