Rust宏编程库yare-macro的使用,yare-macro提供高效编译时代码生成和过程宏开发工具
yare-macro
yare-macro 是为 Yare 实现的宏,Yare 是一个基于过程宏的参数化测试库。
安装
在项目目录中运行以下 Cargo 命令:
cargo add yare-macro
或者在 Cargo.toml 中添加以下行:
yare-macro = "3.0.0"
使用示例
以下是使用 yare-macro 进行参数化测试的完整示例:
use yare_macro::parameterized;
// 测试平方函数
#[parameterized]
#[case(0, 0)] // 输入0,期望输出0
#[case(1, 1)] // 输入1,期望输出1
#[case(2, 4)] // 输入2,期望输出4
#[case(3, 9)] // 输入3,期望输出9
#[case(4, 16)] // 输入4,期望输出16
fn test_square(input: i32, expected: i32) {
assert_eq!(input * input, expected);
}
// 测试加法函数
#[parameterized]
#[case(1, 1, 2)] // 1+1=2
#[case(5, 5, 10)] // 5+5=10
#[case(10, 20, 30)] // 10+20=30
fn test_addition(a: i32, b: i32, expected: i32) {
assert_eq!(a + b, expected);
}
完整示例
以下是更完整的 yare-macro 使用示例,展示更多功能和用例:
use yare_macro::parameterized;
// 测试字符串处理
#[parameterized]
#[case("hello", "HELLO")] // 测试小写转大写
#[case("world", "WORLD")] // 测试小写转大写
#[case("", "")] // 测试空字符串
fn test_to_uppercase(input: &str, expected: &str) {
assert_eq!(input.to_uppercase(), expected);
}
// 测试布尔逻辑
#[parameterized]
#[case(true, false, false)] // true AND false = false
#[case(true, true, true)] // true AND true = true
#[case(false, false, false)] // false AND false = false
fn test_and_operation(a: bool, b: bool, expected: bool) {
assert_eq!(a && b, expected);
}
// 测试浮点数比较(使用近似比较)
#[parameterized]
#[case(0.1 + 0.2, 0.3)] // 浮点数相加
#[case(1.0 / 3.0, 0.333333)] // 浮点数除法
fn test_float_operations(result: f64, expected: f64) {
assert!((result - expected).abs() < 1e-6);
}
// 测试元组作为参数
#[parameterized]
#[case((1, 2), 3)] // 元组解构
#[case((3, 4), 7)]
fn test_tuple_addition(input: (i32, i32), expected: i32) {
assert_eq!(input.0 + input.1, expected);
}
参数化测试说明
- 使用
#[parameterized]
宏标记测试函数 - 每个
#[case]
宏定义一组测试参数 - 测试函数参数与
#[case]
参数一一对应 - 每个
#[case]
会生成独立的测试实例
特性
- 编译时代码生成,无运行时开销
- 支持多种参数类型
- 清晰的测试失败报告
- 与标准 Rust 测试框架无缝集成
文档
更多详细用法请参考官方文档。
许可证
yare-macro 采用 MIT 或 Apache-2.0 双重许可。
1 回复
Rust宏编程库yare-macro使用指南
简介
yare-macro是一个高效的Rust宏编程库,专注于编译时代码生成和简化过程宏开发。它提供了简洁的API和强大的工具集,帮助开发者更容易地创建和使用宏。
主要特性
- 高效的编译时代码生成
- 简化过程宏开发流程
- 提供友好的宏定义语法
- 支持属性宏、派生宏和函数式宏
使用方法
1. 添加依赖
首先在Cargo.toml中添加依赖:
[dependencies]
yare-macro = "0.1"
2. 基本示例:创建属性宏
use yare_macro::attribute;
#[attribute]
fn log_call(item: syn::ItemFn) -> proc_macro2::TokenStream {
let fn_name = &item.sig.ident;
let block = &item.block;
quote::quote! {
fn #fn_name() {
println!("Calling function: {}", stringify!(#fn_name));
#block
}
}
}
// 使用示例
#[log_call]
fn my_function() {
println!("Inside my_function");
}
3. 派生宏示例
use yare_macro::derive;
#[derive]
fn DefaultValue(input: syn::DeriveInput) -> proc_macro2::TokenStream {
let name = &input.ident;
quote::quote! {
impl Default for #name {
fn default() -> Self {
Self {
// 默认字段初始化
}
}
}
}
}
// 使用示例
#[derive(DefaultValue)]
struct MyStruct {
field1: i32,
field2: String,
}
4. 函数式宏示例
use yare_macro::function;
#[function]
fn vec_from(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let elements: Vec<_> = input.into_iter().collect();
quote::quote! {
vec![#(#elements),*]
}
}
// 使用示例
let v = vec_from!(1, 2, 3, 4);
高级用法
1. 宏组合
#[attribute]
fn timed(item: syn::ItemFn) -> proc_macro2::TokenStream {
let fn_name = &item.sig.ident;
let block = &item.block;
quote::quote! {
fn #fn_name() {
let start = std::time::Instant::now();
#block
println!("{} took {:?}", stringify!(#fn_name), start.elapsed());
}
}
}
#[timed]
#[log_call]
fn important_operation() {
// 复杂操作
}
2. 自定义错误处理
#[attribute]
fn non_empty(item: syn::ItemFn) -> Result<proc_macro2::TokenStream, syn::Error> {
if item.block.stmts.is_empty() {
return Err(syn::Error::new_spanned(
&item.sig.ident,
"Function cannot be empty",
));
}
Ok(quote::quote!(#item))
}
性能建议
- 尽量在编译时完成尽可能多的工作
- 使用
syn
和quote
库进行高效的TokenStream处理 - 避免在宏中执行复杂的运行时逻辑
总结
yare-macro为Rust宏开发提供了简洁高效的API,特别适合需要频繁使用宏或开发复杂宏的项目。通过其提供的各种宏类型,可以轻松实现代码生成、元编程和各种DSL开发。
完整示例代码
下面是一个完整的示例,展示如何使用yare-macro创建一个综合项目:
// Cargo.toml
/*
[dependencies]
yare-macro = "0.1"
syn = { version = "1.0", features = ["full"] }
quote = "1.0"
*/
// main.rs
use yare_macro::{attribute, derive, function};
use syn;
use quote::quote;
// 1. 属性宏示例 - 自动添加日志
#[attribute]
pub fn log_call(item: syn::ItemFn) -> proc_macro2::TokenStream {
let fn_name = &item.sig.ident;
let inputs = &item.sig.inputs;
let output = &item.sig.output;
let block = &item.block;
quote! {
fn #fn_name(#inputs) #output {
println!("[LOG] 调用函数: {}", stringify!(#fn_name));
#block
}
}
}
// 2. 派生宏示例 - 自动实现Builder模式
#[derive]
pub fn Builder(input: syn::DeriveInput) -> proc_macro2::TokenStream {
let name = &input.ident;
let builder_name = syn::Ident::new(&format!("{}Builder", name), name.span());
quote! {
impl #name {
pub fn builder() -> #builder_name {
#builder_name::default()
}
}
#[derive(Default)]
struct #builder_name {
// 这里可以添加字段
}
impl #builder_name {
pub fn build(self) -> #name {
#name {
// 这里可以初始化字段
}
}
}
}
}
// 3. 函数式宏示例 - 创建测试用例
#[function]
pub fn test_case(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let test_name = format!("test_{}", input.to_string().replace(" ", "_"));
let test_name = syn::Ident::new(&test_name, proc_macro2::Span::call_site());
quote! {
#[test]
fn #test_name() {
println!("运行测试: {}", stringify!(#test_name));
assert!(#input);
}
}
}
// 使用示例
#[derive(Builder)]
struct User {
id: u64,
name: String,
}
#[log_call]
fn add(a: i32, b: i32) -> i32 {
a + b
}
test_case!(1 + 1 == 2);
fn main() {
let user_builder = User::builder();
let _user = user_builder.build();
println!("1 + 2 = {}", add(1, 2));
}
这个完整示例展示了:
- 使用属性宏自动为函数添加日志功能
- 使用派生宏为结构体自动生成Builder模式
- 使用函数式宏创建测试用例
- 综合使用这些宏的示例
要运行这个示例,需要确保在Cargo.toml中添加了所有必要的依赖项。