Rust插件库yare的使用:轻量级、高效插件系统开发框架
Rust插件库yare的使用:轻量级、高效插件系统开发框架
Yare是一个基于过程宏的参数化测试库,允许使用单个测试定义来测试多种不同的输入场景。测试用例可以通过parameterized
属性来定义,而不是使用test
属性。
特性
- 参数化:指定不同的输入来测试多个场景
- 灵活性:参数化测试用例参数可以是表达式
- 开箱即用:适用于任何Rust版本,无需自定义测试框架
- 可重用性:定义一次测试用例,在不同测试中重复使用
- 可读性:使用熟悉的Rust属性语法保持代码可读性
- 可识别性:每个测试用例都有用户定义的名称
- 经过实战检验:已在多个crate中使用多年
示例代码
第一个示例
fn add5<T: Into<u32>>(component: T) -> u32 {
component.into() + 5
}
#[cfg(test)]
mod tests {
use super::*;
use yare::parameterized;
#[parameterized(
zero_plus_five = { 0, 5 },
one_plus_five = { 1, 6 },
two_plus_five = { 2, 7 },
)]
fn test_add5(input: u16, expected: u32) {
assert_eq!(add5(input), expected);
}
}
带有枚举值的示例
enum Fruit {
Apple,
Bramble(BrambleFruit),
Pear,
}
trait NameOf {
fn name_of(&self) -> &str;
}
impl NameOf for Fruit {
fn name_of(&self) -> &str {
match self {
Fruit::Apple => "apple",
Fruit::Bramble(fruit) => fruit.name_of(),
Fruit::Pear => "pear",
}
}
}
enum BrambleFruit {
Blackberry,
}
impl NameOf for BrambleFruit {
fn name_of(&self) -> &str {
match self {
BrambleFruit::Blackberry => "blackberry",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use yare::parameterized;
#[parameterized(
apple = { Fruit::Apple, "apple" },
pear = { Fruit::Pear, "pear" },
blackberry = { Fruit::Bramble(BrambleFruit::Blackberry), "blackberry" },
)]
fn a_fruity_test(fruit: Fruit, name: &str) {
assert_eq!(fruit.name_of(), name)
}
}
完整示例Demo
use std::sync::atomic::{AtomicU32, Ordering};
use yare::parameterized;
// 模拟掷骰子函数
fn roll_dice(seed: &AtomicU32) -> u8 {
let mut current = seed.load(Ordering::Relaxed);
loop {
let new = current.wrapping_mul(1664525).wrapping_add(1013904223);
match seed.compare_exchange_weak(current, new, Ordering::Relaxed, Ordering::Relaxed) {
Ok(_) => return (new % 6 + 1) as u8, // 返回1-6之间的随机数
Err(e) => current = e,
}
}
}
#[parameterized(
test_case_1 = { roll_dice(&AtomicU32::new(0)), 1 }, // 固定种子测试
test_case_2 = { roll_dice(&AtomicU32::new(42)), 4 }, // 不同种子测试
)]
fn test_dice_roll(seed: u32, expected_min: u8) {
let seed = AtomicU32::new(seed);
let result = roll_dice(&seed);
assert!(result >= expected_min && result <= 6);
}
// 异步测试示例
#[parameterized(
fast_case = { 50, 50 },
slow_case = { 200, 200 },
)]
#[test_macro(tokio::test)]
async fn test_async_sleep(wait_ms: u64, expected_elapsed: u128) {
let start = std::time::Instant::now();
tokio::time::sleep(tokio::time::Duration::from_millis(wait_ms)).await;
let elapsed = start.elapsed().as_millis();
assert!(elapsed >= expected_elapsed);
}
// 带有返回值的测试
#[parameterized(
success_case = { Ok(42) },
error_case = { Err("test error") },
)]
fn test_with_result(result: Result<i32, &str>) -> Result<(), &str> {
let value = result?;
assert_eq!(value, 42);
Ok(())
}
如何使用
- 添加依赖到Cargo.toml:
yare = "3.0.0"
- 在测试模块中使用:
use yare::parameterized;
#[parameterized(
case1 = { param1, param2 },
case2 = { param3, param4 },
)]
fn test_function(arg1: Type1, arg2: Type2) {
// 测试逻辑
}
许可证
Yare采用双许可证:
- MIT许可证
- Apache-2.0许可证
您可以选择其中任一许可证使用。
1 回复
Rust插件库yare的使用:轻量级、高效插件系统开发框架
介绍
yare是一个轻量级的Rust插件系统开发框架,它提供了一种简单高效的方式来构建可扩展的应用程序。yare特别适合需要动态加载和卸载功能的场景,如游戏模组、编辑器插件或任何需要运行时扩展的系统。
主要特点:
- 轻量级设计,最小化开销
- 类型安全的插件接口
- 支持热重载插件
- 简单的API设计
- 跨平台支持
完整示例demo
下面是一个完整的yare插件系统示例,包含主程序和插件实现:
主程序 (main.rs)
use yare::PluginManager;
use std::path::Path;
// 定义插件接口
pub trait Plugin {
fn name(&self) -> &str;
fn on_load(&self);
fn on_unload(&self);
fn execute(&self, input: &str) -> String;
}
fn main() {
// 创建插件管理器
let mut manager = PluginManager::<dyn Plugin>::new();
// 加载插件
#[cfg(target_os = "linux")]
let plugin_path = Path::new("target/debug/libdemo_plugin.so");
#[cfg(target_os = "windows")]
let plugin_path = Path::new("target/debug/demo_plugin.dll");
#[cfg(target_os = "macos")]
let plugin_path = Path::new("target/debug/libdemo_plugin.dylib");
match manager.load(plugin_path) {
Ok(handle) => {
// 获取并使用插件
if let Some(plugin) = manager.get_instance(handle) {
println!("[主程序] 已加载插件: {}", plugin.name());
plugin.on_load();
let result = plugin.execute("测试插件功能");
println!("[主程序] 插件执行结果: {}", result);
plugin.on_unload();
}
// 卸载插件
manager.unload(handle);
}
Err(e) => eprintln!("[主程序] 加载插件失败: {}", e),
}
}
插件实现 (lib.rs)
use yare::plugin_export;
// 使用宏导出插件
#[plugin_export]
pub struct DemoPlugin;
// 实现插件接口
impl super::Plugin for DemoPlugin {
fn name(&self) -> &str {
"DemoPlugin"
}
fn on_load(&self) {
println!("[插件] 已加载");
}
fn on_unload(&self) {
println!("[插件] 已卸载");
}
fn execute(&self, input: &str) -> String {
// 简单的处理逻辑 - 反转字符串并转为大写
let processed = input.chars().rev().collect::<String>().to_uppercase();
format!("处理结果: {}", processed)
}
}
Cargo.toml配置
主程序Cargo.toml:
[package]
name = "yare_demo_host"
version = "0.1.0"
edition = "2021"
[dependencies]
yare = "0.3"
插件Cargo.toml:
[package]
name = "yare_demo_plugin"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"] # 重要:必须设置为cdylib
[dependencies]
yare = "0.3"
构建和运行步骤
- 首先构建插件:
cd yare_demo_plugin
cargo build
- 然后运行主程序:
cd yare_demo_host
cargo run
- 预期输出:
[主程序] 已加载插件: DemoPlugin
[插件] 已加载
[主程序] 插件执行结果: 处理结果: 能功件插试测
[插件] 已卸载
高级功能示例
带配置的插件实现
// 在插件接口中添加
pub trait ConfigurablePlugin: Plugin {
fn configure(&mut self, config: &str);
}
// 在插件实现中添加
#[plugin_export]
pub struct ConfigurableDemoPlugin {
prefix: String,
}
impl ConfigurableDemoPlugin {
pub fn new() -> Self {
Self {
prefix: "默认: ".to_string(),
}
}
}
impl super::Plugin for ConfigurableDemoPlugin {
// ... 其他实现 ...
fn execute(&self, input: &str) -> String {
format!("{}{}", self.prefix, input.to_uppercase())
}
}
impl super::ConfigurablePlugin for ConfigurableDemoPlugin {
fn configure(&mut self, config: &str) {
self.prefix = format!("配置[{}]: ", config);
}
}
注意事项
- 插件和主程序必须使用相同的Rust版本编译
- 类型必须完全一致,包括所有依赖项的版本
- 在Windows上需要注意DLL的加载/卸载策略
- 建议为插件接口设计稳定的ABI
这个完整示例展示了如何使用yare创建一个简单的插件系统,包含插件加载、执行和卸载的全过程。通过这个框架,您可以轻松扩展应用程序的功能,实现动态模块加载。