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),
    })
}

主要功能

  1. 自动生成OpenAPI v2 schema:通过api_v2_schema宏自动为您的结构体生成API文档
  2. 简化API操作定义:使用api_v2_operation宏标记API操作函数
  3. 减少样板代码:自动处理常见的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),
    }
}

使用说明

  1. 首先在项目中添加paperclip-macros依赖
  2. 使用api_v2_schema宏标记需要生成OpenAPI文档的结构体
  3. 使用api_v2_operation宏标记API操作函数
  4. 运行时宏会自动处理相关代码生成工作

注意事项

  1. 确保项目中同时安装了serde和chrono等依赖
  2. 结构体字段可以使用serde属性进行额外控制
  3. 宏会自动根据Rust类型推断OpenAPI类型

1 回复

Rust宏扩展库paperclip-macros使用指南

简介

paperclip-macros是一个简化Rust过程宏开发的库,它提供了更友好的API来编写声明式宏和过程宏,减少样板代码,使宏开发更加直观。

主要特性

  1. 简化过程宏定义语法
  2. 提供更友好的错误报告
  3. 支持声明式宏和属性宏
  4. 内置常用模式匹配和代码生成工具

安装

在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);
}

注意事项

  1. paperclip-macros仍在活跃开发中,API可能会有变化
  2. 错误处理比原生宏更友好,但仍需谨慎处理边界情况
  3. 对于复杂宏,性能可能略低于手写实现

总结

paperclip-macros通过提供更高级的抽象和工具集,显著简化了Rust宏开发过程,特别适合需要快速原型开发或对宏开发不太熟悉的开发者。

回到顶部