Rust宏扩展库paperclip-macros的使用:简化代码生成与过程宏开发的工具
Rust宏扩展库paperclip-macros的使用:简化代码生成与过程宏开发的工具
安装
在项目目录中运行以下Cargo命令:
cargo add paperclip-macros
或者在Cargo.toml中添加以下行:
paperclip-macros = "0.7.0"
示例使用
以下是一个使用paperclip-macros的完整示例:
use paperclip_macros::api_v2_schema;
// 定义一个结构体并使用api_v2_schema宏自动生成OpenAPI v2 schema
#[api_v2_schema]
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: i64,
username: String,
email: String,
#[serde(skip_serializing_if = "Option::is_none")]
bio: Option<String>,
created_at: chrono::DateTime<chrono::Utc>,
}
// 使用宏自动生成API响应模型
#[api_v2_schema]
#[derive(Debug, Serialize)]
struct UsersResponse {
users: Vec<User>,
total: usize,
page: usize,
per_page: usize,
}
// 为REST API生成操作定义
#[api_v2_operation]
fn get_users(page: Option<usize>, per_page: Option<usize>) -> Result<UsersResponse, Error> {
// 实际业务逻辑...
Ok(UsersResponse {
users: vec![User {
id: 1,
username: "testuser".to_string(),
email: "test@example.com".to_string(),
bio: Some("Just a test user".to_string()),
created_at: chrono::Utc::now(),
}],
total: 1,
page: page.unwrap_or(1),
per_page: per_page.unwrap_or(10),
})
}
主要功能
- 自动生成OpenAPI v2 schema:通过
api_v2_schema
宏自动为您的结构体生成API文档 - 简化API操作定义:使用
api_v2_operation
宏标记API操作函数 - 减少样板代码:自动处理常见的API相关代码生成
许可证
paperclip-macros采用MIT或Apache-2.0双重许可证。
完整示例代码
// 1. 添加必要的依赖到Cargo.toml
// [dependencies]
// paperclip-macros = "0.7.0"
// serde = { version = "1.0", features = ["derive"] }
// chrono = "0.4"
use paperclip_macros::{api_v2_schema, api_v2_operation};
use serde::{Serialize, Deserialize};
use chrono;
// 定义用户数据结构
#[api_v2_schema]
#[derive(Debug, Serialize, Deserialize)]
pub struct User {
/// 用户ID
id: i64,
/// 用户名
username: String,
/// 电子邮件
email: String,
/// 用户简介(可选)
#[serde(skip_serializing_if = "Option::is_none")]
bio: Option<String>,
/// 创建时间
created_at: chrono::DateTime<chrono::Utc>,
}
// 定义API响应结构
#[api_v2_schema]
#[derive(Debug, Serialize)]
pub struct UsersResponse {
/// 用户列表
users: Vec<User>,
/// 总用户数
total: usize,
/// 当前页码
page: usize,
/// 每页数量
per_page: usize,
}
// 定义API操作
#[api_v2_operation]
/// 获取用户列表
///
/// # 参数
/// * `page` - 页码(可选)
/// * `per_page` - 每页数量(可选)
///
/// # 返回值
/// 返回包含用户列表的响应或错误
fn get_users(page: Option<usize>, per_page: Option<usize>) -> Result<UsersResponse, String> {
// 模拟从数据库获取数据
let mock_user = User {
id: 1,
username: "testuser".to_string(),
email: "test@example.com".to_string(),
bio: Some("Just a test user".to_string()),
created_at: chrono::Utc::now(),
};
Ok(UsersResponse {
users: vec![mock_user],
total: 1,
page: page.unwrap_or(1),
per_page: per_page.unwrap_or(10),
})
}
fn main() {
// 模拟API调用
match get_users(Some(1), Some(10)) {
Ok(response) => println!("成功获取用户: {:?}", response),
Err(e) => println!("获取用户失败: {}", e),
}
}
使用说明
- 首先在项目中添加paperclip-macros依赖
- 使用
api_v2_schema
宏标记需要生成OpenAPI文档的结构体 - 使用
api_v2_operation
宏标记API操作函数 - 运行时宏会自动处理相关代码生成工作
注意事项
- 确保项目中同时安装了serde和chrono等依赖
- 结构体字段可以使用serde属性进行额外控制
- 宏会自动根据Rust类型推断OpenAPI类型
1 回复
Rust宏扩展库paperclip-macros使用指南
简介
paperclip-macros是一个简化Rust过程宏开发的库,它提供了更友好的API来编写声明式宏和过程宏,减少样板代码,使宏开发更加直观。
主要特性
- 简化过程宏定义语法
- 提供更友好的错误报告
- 支持声明式宏和属性宏
- 内置常用模式匹配和代码生成工具
安装
在Cargo.toml中添加依赖:
[dependencies]
paperclip-macros = "0.1"
基本使用方法
1. 定义属性宏
use paperclip_macros::attribute_macro;
#[attribute_macro]
pub fn my_attribute_macro(attr: TokenStream, item: TokenStream) -> TokenStream {
// 处理逻辑
quote! {
#item
}
}
2. 定义派生宏
use paperclip_macros::derive_macro;
#[derive_macro]
pub fn my_derive_macro(input: TokenStream) -> TokenStream {
// 处理逻辑
quote! {
impl SomeTrait for #input {
// 生成的实现
}
}
}
3. 使用声明式宏
use paperclip_macros::decl_macro;
decl_macro! {
($name:ident) => {
struct $name;
}
}
// 使用
my_macro!(MyStruct); // 生成 struct MyStruct;
高级用法示例
自定义错误报告
use paperclip_macros::{attribute_macro, Diagnostic};
#[attribute_macro]
pub fn validate_struct(attr: TokenStream, item: TokenStream) -> TokenStream {
// 解析输入
let input = parse_macro_input!(item as DeriveInput);
// 检查结构体是否有命名字段
if let Data::Struct(data) = &input.data {
if data.fields.iter().all(|f| f.ident.is_none()) {
Diagnostic::error("This attribute requires named fields")
.span(input.span())
.emit();
return TokenStream::new();
}
}
// 生成代码...
}
模式匹配辅助
use paperclip_macros::{attribute_macro, Pattern};
#[attribute_macro]
pub fn auto_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
// 使用模式匹配简化处理
match Pattern::from(input) {
Pattern::Struct(name, fields) => {
// 处理结构体
}
Pattern::Enum(name, variants) => {
// 处理枚举
}
_ => {
Diagnostic::error("Unsupported item type").emit();
return TokenStream::new();
}
}
}
实际应用示例
生成Builder模式
use paperclip-macros::{derive_macro, Pattern};
#[derive_macro]
pub fn builder(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let Pattern::Struct(name, fields) = Pattern::from(input) else {
panic!("Builder macro only works on structs");
};
let builder_name = format_ident!("{}Builder", name);
let setter_methods = fields.iter().map(|f| {
let field_name = &f.ident;
let field_type = &f.ty;
quote! {
pub fn #field_name(mut self, value: #field_type) -> Self {
self.#field_name = Some(value);
self
}
}
});
quote! {
pub struct #builder_name {
#( #fields: Option<#field_type> ),*
}
impl #builder_name {
#( #setter_methods )*
pub fn build(self) -> Result<#name, String> {
Ok(#name {
#( #field_name: self.#field_name.ok_or(format!("field {} not set", stringify!(#field_name)))? ),*
})
}
}
impl #name {
pub fn builder() -> #builder_name {
#builder_name {
#( #field_name: None ),*
}
}
}
}
}
完整示例Demo
下面是一个完整的Builder模式实现示例,展示如何使用paperclip-macros:
use paperclip_macros::{derive_macro, Pattern};
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[derive_macro]
pub fn builder(input: TokenStream) -> TokenStream {
// 解析输入的结构体定义
let input = parse_macro_input!(input as DeriveInput);
// 使用Pattern匹配结构体
let Pattern::Struct(struct_name, fields) = Pattern::from(input) else {
panic!("Builder宏只能用于结构体");
};
// 生成Builder结构体名称
let builder_name = format_ident!("{}Builder", struct_name);
// 为每个字段生成setter方法
let setter_methods = fields.iter().map(|f| {
let field_name = &f.ident;
let field_type = &f.ty;
quote! {
pub fn #field_name(mut self, value: #field_type) -> Self {
self.#field_name = Some(value);
self
}
}
});
// 生成完整的Builder实现代码
let expanded = quote! {
// 定义Builder结构体
pub struct #builder_name {
#( #fields: Option<#field_type> ),*
}
// 实现Builder方法
impl #builder_name {
#( #setter_methods )*
// build方法用于最终构建目标结构体
pub fn build(self) -> Result<#struct_name, String> {
Ok(#struct_name {
#( #field_name: self.#field_name.ok_or(format!("字段{}未设置", stringify!(#field_name)))? ),*
})
}
}
// 为原结构体添加builder()方法
impl #struct_name {
pub fn builder() -> #builder_name {
#builder_name {
#( #field_name: None ),*
}
}
}
};
// 返回生成的TokenStream
expanded.into()
}
使用示例:
#[derive(Builder)]
struct User {
id: u64,
name: String,
email: String,
}
fn main() {
let user = User::builder()
.id(1)
.name("Alice".to_string())
.email("alice@example.com".to_string())
.build()
.unwrap();
println!("User created: {:?}", user);
}
注意事项
- paperclip-macros仍在活跃开发中,API可能会有变化
- 错误处理比原生宏更友好,但仍需谨慎处理边界情况
- 对于复杂宏,性能可能略低于手写实现
总结
paperclip-macros通过提供更高级的抽象和工具集,显著简化了Rust宏开发过程,特别适合需要快速原型开发或对宏开发不太熟悉的开发者。