Rust插件库yada的使用,高效扩展Rust功能的插件管理与增强工具
Yada: 另一个双数组
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"
最佳实践
- 接口设计:定义稳定且向后兼容的插件接口
- 版本控制:为每个插件实现版本检查
- 错误处理:妥善处理插件加载和使用中的错误
- 资源清理:确保插件卸载时释放所有资源
- 安全考虑:仅从可信来源加载动态插件
注意事项
- 动态插件加载在WebAssembly目标上不可用
- 插件接口应该尽量保持稳定,避免频繁变更
- 在生产环境中使用前,充分测试插件的兼容性和稳定性
yada为Rust应用程序提供了灵活的插件系统,使得功能扩展和模块化开发变得更加简单和安全。