Rust插件库ph的使用,高效功能扩展与模块化开发工具

Rust插件库ph的使用,高效功能扩展与模块化开发工具

ph 是由 Piotr Beling 开发的 Rust 库,提供了(最小)完美哈希函数的实现。

最小完美哈希函数(MPHF)是从键集 K 到集合 {0, 1, …, |K|−1} 的双射。

该库包含以下实现:

  • PHast – 基于桶放置的函数,具有非常快速的评估和低于每键2位的存储大小
  • 两种指纹最小完美哈希函数的变体:
    • 不带群优化的(FMPH, fmph::Function)
    • 带群优化的(FMPHGO, fmph::GOFunction)

所有这些函数都可以为任何预先给定的可哈希项集 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"]

构建和运行步骤

  1. 首先构建共享接口crate:
cd shared && cargo build
  1. 构建插件:
cd plugins/english_greeter && cargo build
cd ../chinese_greeter && cargo build
  1. 运行主程序:
cd ../.. && cargo run

注意事项

  1. 插件和主程序需要使用相同的Rust版本编译
  2. 类型定义需要在单独的crate中共享给主程序和插件
  3. 避免在插件和主程序之间传递复杂类型
  4. 注意内存安全,插件卸载后不应再使用其提供的对象

ph库为Rust带来了强大的模块化开发能力,特别适合需要灵活扩展的大型应用系统。通过合理的架构设计,可以构建出既保持高性能又易于维护的插件化应用。

回到顶部