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

Yada: 另一个双数组

crate-name at crates.io crate-name at docs.rs

Yada 是另一个双数组字典树库,旨在实现快速搜索和紧凑的数据表示。

特性

  • 构建静态双数组字典树
    • Yada 采用类似 Darts-clone 的双数组节点的紧凑二进制表示。
  • 公共前缀搜索
    • 该方法返回一个 Iterator,这是一种无需堆分配即可查找多个值的有效方式。
  • 精确匹配搜索
    • 该方法以 Option 形式查找与精确匹配键关联的值。

要求

  • Rust 版本 >= 1.46.0

用法

更多详情请参阅示例代码。

构建双数组字典树

use yada::builder::DoubleArrayBuilder;

// 创建一个包含键值对的键集
let keyset = &[
    ("a".as_bytes(), 0),
    ("ab".as_bytes(), 1),
    ("abc".as_bytes(), 2),
    ("b".as_bytes(), 3),
    ("bc".as_bytes(), 4),
    ("c".as_bytes(), 5),
];

// 构建双数组字典树二进制数据
let da_bytes: Option<Vec<u8>> = DoubleArrayBuilder::build(keyset);

通过键搜索条目

use yada::DoubleArray;

// 创建双数组字典树实例
let da = DoubleArray::new(da_bytes.unwrap());

// 精确匹配搜索
for (key, value) in keyset {
    assert_eq!(da.exact_match_search(key), Some(*value as u32));
}
assert_eq!(da.exact_match_search("abc".as_bytes()), Some(2));
assert_eq!(da.exact_match_search("abcd".as_bytes()), None);

// 公共前缀搜索
assert_eq!(
    da.common_prefix_search("abcd".as_bytes())
        .collect::<Vec<_>>(),
    vec![(0, 1), (1, 2), (2, 3)] // 匹配 "a", "ab", "abc", 值和键长度
);
assert_eq!(
    da.common_prefix_search("d".as_bytes()).collect::<Vec<_>>(),
    vec![] // 不匹配
);

限制

  • 值必须表示为 31 位无符号整数,类型为 u32
    • Yada 使用最高有效位(MSB)作为标志来区分值节点和其他节点。
  • 双数组节点的偏移量为 29 位宽,因此最多可表示约 5.36 亿个节点。
    • 这意味着此限制导致双数组的大小上限约为 2GB。

许可证

根据以下任一许可证授权:

  • Apache License, Version 2.0
  • MIT license

由您选择。

贡献

除非您明确说明,否则根据 Apache-2.0 许可证定义,您为包含在该工作中而有意提交的任何贡献均应按照上述双重许可,无需任何附加条款或条件。

参考文献

  • Aoe, J. An Efficient Digital Search Algorithm by Using a Double-Array Structure. IEEE Transactions on Software Engineering. Vol. 15, 9 (Sep 1989). pp. 1066-1077.
  • Darts: Double ARray Trie System
  • Darts-clone: A clone of Darts (Double-ARray Trie System)

完整示例代码

use yada::builder::DoubleArrayBuilder;
use yada::DoubleArray;

fn main() {
    // 创建一个包含键值对的键集
    let keyset = &[
        ("a".as_bytes(), 0),    // 键"a"对应值0
        ("ab".as_bytes(), 1),   // 键"ab"对应值1
        ("abc".as_bytes(), 2),  // 键"abc"对应值2
        ("b".as_bytes(), 3),    // 键"b"对应值3
        ("bc".as_bytes(), 4),   // 键"bc"对应值4
        ("c".as_bytes(), 5),    // 键"c"对应值5
    ];

    // 构建双数组字典树二进制数据
    let da_bytes: Option<Vec<u8>> = DoubleArrayBuilder::build(keyset);
    let da = DoubleArray::new(da_bytes.unwrap());

    // 精确匹配搜索测试
    for (key, value) in keyset {
        assert_eq!(da.exact_match_search(key), Some(*value as u32));
    }
    assert_eq!(da.exact_match_search("abc".as_bytes()), Some(2));
    assert_eq!(da.exact_match_search("abcd".as_bytes()), None);

    // 公共前缀搜索测试
    assert_eq!(
        da.common_prefix_search("abcd".as_bytes())
            .collect::<Vec<_>>(),
        vec![(0, 1), (1, 2), (2, 3)] // 匹配 "a", "ab", "abc", 值和键长度
    );
    assert_eq!(
        da.common_prefix_search("d".as_bytes()).collect::<Vec<_>>(),
        vec![] // 不匹配
    );
}

1 回复

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

概述

yada是一个专为Rust设计的插件管理与功能增强工具,通过动态加载和统一管理插件,帮助开发者轻松扩展应用程序功能。它提供了安全的插件接口、版本兼容性检查和运行时加载机制,适用于需要模块化架构的Rust项目。

核心特性

  • 动态插件加载:支持运行时加载和卸载插件
  • 类型安全接口:通过Traits定义插件契约,确保类型安全
  • 依赖管理:自动处理插件间依赖关系
  • 生命周期管理:完整的插件初始化、运行和清理周期
  • 跨平台支持:支持Windows、Linux和macOS系统

安装方法

在Cargo.toml中添加依赖:

[dependencies]
yada = "0.3.0"

基本使用方法

1. 定义插件接口

use yada::Plugin;

pub trait CalculatorPlugin: Plugin {
    fn calculate(&self, a: f64, b: f64) -> f64;
    fn get_operation_name(&self) -> &'static str;
}

2. 实现插件

#[derive(Default)]
struct AdditionPlugin;

impl Plugin for AdditionPlugin {
    fn name(&self) -> &'static str {
        "addition_plugin"
    }
    
    fn version(&self) -> &'static str {
        "1.0.0"
    }
}

impl CalculatorPlugin for AdditionPlugin {
    fn calculate(&self, a: f64, b: f64) -> f64 {
        a + b
    }
    
    fn get_operation_name(&self) -> &'static str {
        "addition"
    }
}

3. 注册和使用插件

use yada::PluginManager;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut manager = PluginManager::new();
    
    // 注册插件
    manager.register_plugin(Box::new(AdditionPlugin::default()));
    
    // 加载动态库插件(可选)
    #[cfg(not(target_arch = "wasm32"))]
    manager.load_dynamic("path/to/plugin.so")?;
    
    // 使用插件
    if let Some(calc_plugin) = manager.get_plugin::<dyn CalculatorPlugin>("addition_plugin") {
        let result = calc_plugin.calculate(5.0, 3.0);
        println!("5 + 3 = {}", result);
    }
    
    Ok(())
}

4. 构建动态插件

创建独立的插件crate:

# 在插件项目的Cargo.toml中
[lib]
crate-type = ["cdylib"]

[dependencies]
yada = "0.3.0"
your_main_crate = { path = "../main_crate" }
// 在lib.rs中
use yada::Plugin;
use your_main_crate::CalculatorPlugin;

#[derive(Default)]
struct MultiplicationPlugin;

impl Plugin for MultiplicationPlugin {
    fn name(&self) -> &'static str {
        "multiplication_plugin"
    }
}

impl CalculatorPlugin for MultiplicationPlugin {
    fn calculate(&self, a: f64, b: f64) -> f64 {
        a * b
    }
    
    fn get_operation_name(&self) -> &'static str {
        "multiplication"
    }
}

// 必须提供的导出函数
#[no_mangle]
pub extern "C" fn _yada_create_plugin() -> *mut dyn Plugin {
    Box::into_raw(Box::new(MultiplicationPlugin::default()))
}

高级用法

插件配置

use yada::PluginConfig;

let config = PluginConfig {
    auto_reload: true,
    watch_interval: std::time::Duration::from_secs(5),
    ..Default::default()
};

let mut manager = PluginManager::with_config(config);

错误处理

match manager.load_dynamic("plugin.so") {
    Ok(()) => println!("Plugin loaded successfully"),
    Err(e) => eprintln!("Failed to load plugin: {}", e),
}

完整示例demo

// main.rs
use yada::PluginManager;

// 定义插件接口
pub trait CalculatorPlugin: yada::Plugin {
    fn calculate(&self, a: f64, b: f64) -> f64;
    fn get_operation_name(&self) -> &'static str;
}

// 实现加法插件
#[derive(Default)]
struct AdditionPlugin;

impl yada::Plugin for AdditionPlugin {
    fn name(&self) -> &'static str {
        "addition_plugin"
    }
    
    fn version(&self) -> &'static str {
        "1.0.0"
    }
}

impl CalculatorPlugin for AdditionPlugin {
    fn calculate(&self, a: f64, b: f64) -> f64 {
        a + b
    }
    
    fn get_operation_name(&self) -> &'static str {
        "addition"
    }
}

// 实现减法插件
#[derive(Default)]
struct SubtractionPlugin;

impl yada::Plugin for SubtractionPlugin {
    fn name(&self) -> &'static str {
        "subtraction_plugin"
    }
    
    fn version(&self) -> &'static str {
        "1.0.0"
    }
}

impl CalculatorPlugin for SubtractionPlugin {
    fn calculate(&self, a: f64, b: f64) -> f64 {
        a - b
    }
    
    fn get_operation_name(&self) -> &'static str {
        "subtraction"
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut manager = PluginManager::new();
    
    // 注册内置插件
    manager.register_plugin(Box::new(AdditionPlugin::default()));
    manager.register_plugin(Box::new(SubtractionPlugin::default()));
    
    // 测试所有插件
    let test_cases = vec![(5.0, 3.0), (10.0, 4.0), (7.0, 2.0)];
    
    for (a, b) in test_cases {
        println!("\n计算 {} 和 {}:", a, b);
        
        // 获取所有CalculatorPlugin类型的插件
        let plugins = manager.get_plugins::<dyn CalculatorPlugin>();
        
        for plugin in plugins {
            let result = plugin.calculate(a, b);
            println!("{}: {} {} {} = {}", 
                    plugin.name(), 
                    a, 
                    plugin.get_operation_name(), 
                    b, 
                    result);
        }
    }
    
    Ok(())
}
# Cargo.toml
[package]
name = "yada-example"
version = "0.1.0"
edition = "2021"

[dependencies]
yada = "0.3.0"

最佳实践

  1. 接口设计:定义稳定且向后兼容的插件接口
  2. 版本控制:为每个插件实现版本检查
  3. 错误处理:妥善处理插件加载和使用中的错误
  4. 资源清理:确保插件卸载时释放所有资源
  5. 安全考虑:仅从可信来源加载动态插件

注意事项

  • 动态插件加载在WebAssembly目标上不可用
  • 插件接口应该尽量保持稳定,避免频繁变更
  • 在生产环境中使用前,充分测试插件的兼容性和稳定性

yada为Rust应用程序提供了灵活的插件系统,使得功能扩展和模块化开发变得更加简单和安全。

回到顶部