Rust插件库ph的使用,高效功能扩展与模块化开发工具
Rust插件库ph的使用,高效功能扩展与模块化开发工具
ph
是由 Piotr Beling 开发的 Rust 库,提供了(最小)完美哈希函数的实现。
最小完美哈希函数(MPHF)是从键集 K 到集合 {0, 1, …, |K|−1} 的双射。
该库包含以下实现:
- PHast – 基于桶放置的函数,具有非常快速的评估和低于每键2位的存储大小
- 两种指纹最小完美哈希函数的变体:
- 不带群优化的(FMPH,
fmph::Function
) - 带群优化的(FMPHGO,
fmph::GOFunction
)
- 不带群优化的(FMPH,
所有这些函数都可以为任何预先给定的可哈希项集 K 构建。
示例
以下是使用 fmph::Function
的基本示例:
use ph::fmph;
let keys = ['a', 'b', 'z'];
let f = fmph::Function::from(keys.as_ref());
// f为每个键分配一个来自集合{0, 1, 2}的唯一数字
for k in keys { println!("The key {} is assigned the value {}.", k, f.get(&k).unwrap()); }
let mut values = [f.get(&'a').unwrap(), f.get(&'b').unwrap(), f.get(&'z').unwrap()];
values.sort();
assert_eq!(values, [0, 1, 2]);
使用 fmph::Function
和 bitmap 来表示给定可哈希元素集的子集的示例:
use ph::fmph;
use bitm::{BitAccess, BitVec}; // bitm用于操作位图
use std::hash::Hash;
pub struct Subset { // 表示给定集合的子集
hash: fmph::Function, // 将集合元素双射到位图的位
bitmap: Box<[u64]> // 哈希指向的位为1 <=> 元素在子集中
}
impl Subset {
pub fn of<E: Hash + Sync>(set: &[E]) -> Self { // 构建给定集合的空子集
Subset {
hash: set.into(),
bitmap: Box::with_zeroed_bits(set.len())
}
}
pub fn contain<E: Hash>(&self, e: &E) -> bool { // 检查e是否在子集中
self.bitmap.get_bit(self.hash.get_or_panic(e) as usize) as bool
}
pub fn insert<E: Hash(&mut self, e: &E) { // 将e插入子集
self.bitmap.set_bit(self.hash.get_or_panic(e) as usize)
}
pub fn remove<E: Hash>(&mut self, e: &E) { // 从子集中移除e
self.bitmap.clear_bit(self.hash.get_or_panic(e) as usize)
}
pub fn len(&self) -> usize { // 返回子集中的元素数量
self.bitmap.count_bit_ones()
}
}
let mut subset = Subset::of(["alpha", "beta", "gamma"].as_ref());
assert_eq!(subset.len(), 0);
assert!(!subset.contain(&"alpha"));
assert!(!subset.contain(&"beta"));
subset.insert(&"beta");
subset.insert(&"gamma");
assert_eq!(subset.len(), 2);
assert!(subset.contain(&"beta"));
subset.remove(&"beta");
assert_eq!(subset.len(), 1);
assert!(!subset.contain(&"beta"));
// subset.insert(&"zeta"); // 可能会panic或将任何项插入子集
完整示例
下面是一个更完整的示例,展示了如何使用 ph
库进行高效的数据查询和存储:
use ph::fmph;
use std::collections::HashMap;
// 定义一个学生结构体
#[derive(Hash)]
struct Student {
id: u32,
name: String,
}
fn main() {
// 创建学生数据集
let students = vec![
Student { id: 1001, name: "Alice".to_string() },
Student { id: 1002, name: "Bob".to_string() },
Student { id: 1003, name: "Charlie".to_string() },
];
// 构建完美哈希函数
let f = fmph::Function::from(students.as_ref());
// 创建成绩存储映射
let mut scores = HashMap::new();
// 为每个学生分配成绩
for (i, student) in students.iter().enumerate() {
let hash_value = f.get(student).unwrap();
scores.insert(hash_value, (80 + i) as f32); // 模拟成绩
}
// 查询特定学生的成绩
let bob = Student { id: 1002, name: "Bob".to_string() };
if let Some(score) = scores.get(&f.get(&bob).unwrap()) {
println!("Bob's score is: {}", score);
}
// 打印所有学生信息
for student in &students {
let hash = f.get(student).unwrap();
println!("ID: {}, Name: {}, Hash: {}, Score: {}",
student.id, student.name, hash, scores[&hash]);
}
// 验证哈希的唯一性
let mut hashes: Vec<_> = students.iter()
.map(|s| f.get(s).unwrap())
.collect();
hashes.sort_unstable();
assert_eq!(hashes, vec![0, 1, 2]);
}
特性
- PHast 提供极快的评估速度
- FMPH 和 FMPHGO 分别使用约2.8和2.1位/键
- 所有函数都是O(1)时间复杂度
- 构建过程需要很少的辅助空间
- 可以并行化构建
- 支持不将键保留在内存中的构建方式
安装
在项目目录中运行以下Cargo命令:
cargo add ph
或在Cargo.toml中添加:
ph = "0.9.6"
许可证
MIT OR Apache-2.0
1 回复
Rust插件库ph
的使用:高效功能扩展与模块化开发工具
介绍
ph
是一个Rust语言的插件库,旨在为开发者提供高效的模块化开发体验和功能扩展能力。它通过动态加载和热插拔机制,使得应用程序可以在运行时加载、卸载和更新功能模块,非常适合需要插件架构的大型项目或需要频繁功能迭代的应用场景。
主要特性
- 动态加载:支持在运行时加载和卸载插件
- 模块隔离:每个插件运行在独立的环境中,互不干扰
- 类型安全:通过Rust的强类型系统保证插件接口的安全性
- 跨平台:支持Windows、Linux和macOS等主流操作系统
- 生命周期管理:提供完整的插件生命周期管理能力
安装方法
在Cargo.toml
中添加依赖:
[dependencies]
ph = "0.3.0"
完整示例
下面是一个完整的示例,展示如何使用ph
库创建插件系统:
项目结构
my_plugin_system/
├── Cargo.toml
├── src/
│ └── main.rs
└── plugins/
├── english_greeter/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
└── chinese_greeter/
├── Cargo.toml
└── src/
└── lib.rs
1. 共享接口定义 (放在独立crate中)
// shared/src/lib.rs
use ph::{Plugin, PluginInterface};
#[derive(PluginInterface)]
pub trait Greeter {
fn greet(&self, name: &str) -> String;
}
2. 英语问候插件实现
// plugins/english_greeter/src/lib.rs
use shared::Greeter;
use ph::Plugin;
#[derive(Default)]
struct EnglishGreeter;
impl Plugin for EnglishGreeter {
fn name(&self) -> &str {
"english_greeter"
}
}
impl Greeter for EnglishGreeter {
fn greet(&self, name: &str) -> String {
format!("Hello, {}!", name)
}
}
#[no_mangle]
pub extern "C" fn _plugin_create() -> Box<dyn Greeter> {
Box::new(EnglishGreeter::default())
}
3. 中文问候插件实现
// plugins/chinese_greeter/src/lib.rs
use shared::Greeter;
use ph::Plugin;
#[derive(Default)]
struct ChineseGreeter;
impl Plugin for ChineseGreeter {
fn name(&self) -> &str {
"chinese_greeter"
}
}
impl Greeter for ChineseGreeter {
fn greet(&self, name: &str) -> String {
format!("你好,{}!", name)
}
}
#[no_mangle]
pub extern "C" fn _plugin_create() -> Box<dyn Greeter> {
Box::new(ChineseGreeter::default())
}
4. 主程序实现
// src/main.rs
use ph::PluginManager;
use shared::Greeter;
use std::path::Path;
fn main() {
let mut manager = PluginManager::new();
// 加载英语问候插件
manager.load_plugin(Path::new("plugins/english_greeter/target/debug/libenglish_greeter.so")).unwrap();
// 加载中文问候插件
manager.load_plugin(Path::new("plugins/chinese_greeter/target/debug/libchinese_greeter.so")).unwrap();
// 使用英语问候插件
let english = manager.get_plugin::<dyn Greeter>("english_greeter").unwrap();
println!("{}", english.greet("World"));
// 使用中文问候插件
let chinese = manager.get_plugin::<dyn Greeter>("chinese_greeter").unwrap();
println!("{}", chinese.greet("世界"));
// 卸载插件
manager.unload_plugin("english_greeter").unwrap();
manager.unload_plugin("chinese_greeter").unwrap();
}
5. 插件Cargo.toml配置示例
# plugins/english_greeter/Cargo.toml
[package]
name = "english_greeter"
version = "0.1.0"
[dependencies]
ph = "0.3.0"
shared = { path = "../../shared" }
[lib]
crate-type = ["cdylib"]
构建和运行步骤
- 首先构建共享接口crate:
cd shared && cargo build
- 构建插件:
cd plugins/english_greeter && cargo build
cd ../chinese_greeter && cargo build
- 运行主程序:
cd ../.. && cargo run
注意事项
- 插件和主程序需要使用相同的Rust版本编译
- 类型定义需要在单独的crate中共享给主程序和插件
- 避免在插件和主程序之间传递复杂类型
- 注意内存安全,插件卸载后不应再使用其提供的对象
ph
库为Rust带来了强大的模块化开发能力,特别适合需要灵活扩展的大型应用系统。通过合理的架构设计,可以构建出既保持高性能又易于维护的插件化应用。