Rust插件库bae的使用:高效扩展Rust功能的轻量级工具包

Rust插件库bae的使用:高效扩展Rust功能的轻量级工具包

bae是一个为proc macro作者设计的crate,它简化了属性的解析过程。虽然受到darling的启发,但提供了更简单的API。

安装

在项目目录中运行以下Cargo命令:

cargo add bae

或者在你的Cargo.toml中添加以下行:

bae = "0.1.7"

示例用法

下面是一个使用bae的完整示例demo,展示如何定义和解析自定义属性:

use bae::FromAttributes;
use syn::{parse_macro_input, DeriveInput};

// 定义一个可以解析的结构体
#[derive(FromAttributes)]
struct MyAttributes {
    #[bae(default)]
    name: Option<String>,
    
    #[bae(default = "0")]
    count: usize,
    
    enabled: bool,
}

// 自定义派生宏示例
#[proc_macro_derive(MyDerive, attributes(my_attr))]
pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    
    // 解析属性
    let attrs = MyAttributes::from_attributes(&input.attrs).unwrap();
    
    // 使用解析出的属性
    println!("name: {:?}", attrs.name);
    println!("count: {}", attrs.count);
    println!("enabled: {}", attrs.enabled);
    
    proc_macro::TokenStream::new()
}

在这个示例中:

  1. 我们定义了一个MyAttributes结构体,使用#[derive(FromAttributes)]自动实现属性解析
  2. 结构体字段可以有不同的属性:
    • name字段是可选的(Option),如果没有提供则默认为None
    • count字段有默认值"0"
    • enabled字段是必须提供的
  3. 在proc macro中,我们可以轻松地从DeriveInput中解析出这些属性

bae的设计目标是保持简单和轻量级,同时提供必要的功能来解析proc macro中的属性。它特别适合那些需要自定义属性但不想处理复杂解析逻辑的macro作者。

完整示例代码

下面是一个更完整的示例,展示如何使用bae创建一个自定义派生宏:

// 导入必要的库
use bae::FromAttributes;
use syn::{parse_macro_input, DeriveInput};
use quote::quote;

// 定义属性结构体
#[derive(FromAttributes)]
struct MyConfig {
    #[bae(default = "\"default_name\".to_string()")]
    name: String,
    
    #[bae(default)]
    id: Option<u32>,
    
    #[bae(default = "true")]
    debug: bool,
}

// 自定义派生宏实现
#[proc_macro_derive(MyMacro, attributes(my_config))]
pub fn my_macro_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    // 解析输入为DeriveInput
    let input = parse_macro_input!(input as DeriveInput);
    
    // 解析自定义属性
    let config = MyConfig::from_attributes(&input.attrs)
        .expect("Failed to parse attributes");
    
    // 获取结构体名称
    let name = input.ident;
    
    // 生成实现代码
    let expanded = quote! {
        impl #name {
            fn print_config(&self) {
                println!("Name: {}", #config.name);
                println!("ID: {:?}", #config.id);
                println!("Debug mode: {}", #config.debug);
            }
        }
    };
    
    // 返回生成的token stream
    proc_macro::TokenStream::from(expanded)
}

这个示例展示了:

  1. 如何定义带有默认值的属性配置
  2. 如何处理可选属性
  3. 如何使用quote crate生成代码
  4. 如何将解析的属性应用到生成的代码中

使用示例:

#[derive(MyMacro)]
#[my_config(name = "custom_name", id = 42)]
struct MyStruct;

let s = MyStruct;
s.print_config();
// 输出:
// Name: custom_name
// ID: Some(42)
// Debug mode: true

1 回复

Rust插件库bae的使用:高效扩展Rust功能的轻量级工具包

简介

bae是一个轻量级的Rust插件库,旨在通过简单易用的接口扩展Rust的核心功能。它提供了一系列实用工具和扩展方法,可以帮助开发者提高编码效率,减少样板代码。

主要特性

  • 轻量级设计,无额外依赖
  • 提供常用功能的扩展实现
  • 简化常见编程模式
  • 完全兼容标准库

安装方法

在Cargo.toml中添加依赖:

[dependencies]
bae = "0.3.0"

核心功能及使用示例

1. 集合操作扩展

use bae::collections::ExtendedIter;

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    // 查找并转换
    let result = numbers.find_map(|x| if x > 3 { Some(x * 2) } else { None });
    println!("{:?}", result); // 输出: Some(8)
    
    // 安全获取
    let safe_get = numbers.get_or(2, &99);
    println!("{}", safe_get); // 输出: 3
    
    let safe_get = numbers.get_or(10, &99);
    println!("{}", safe_get); // 输出: 99
}

2. 字符串处理

use bae::string::StringExt;

fn main() {
    let s = "hello world".to_string();
    
    // 安全截取
    println!("{}", s.safe_slice(0..5)); // 输出: hello
    println!("{}", s.safe_slice(6..15)); // 输出: world (自动处理越界)
    
    // 快速重复
    println!("{}", s.repeat_to(3)); // 输出: hello worldhello worldhello world
}

3. Option和Result扩展

use bae::option::OptionExt;
use bae::result::ResultExt;

fn main() {
    // Option扩展
    let some_val: Option<i32> = Some(42);
    let none_val: Option<i32> = None;
    
    println!("{}", some_val.unwrap_or_default()); // 输出: 42
    println!("{}", none_val.unwrap_or_default()); // 输出: 0
    
    // Result扩展
    let ok_result: Result<i32, &str> = Ok(42);
    let err_result: Result<i32, &str> = Err("error");
    
    println!("{:?}", ok_result.map_err_to_string()); // 输出: Ok(42)
    println!("{:?}", err_result.map_err_to_string()); // 输出: Err("error")
}

4. 数学运算扩展

use bae::num::NumExt;

fn main() {
    // 数字扩展
    let x = 5;
    
    println!("{}", x.clamp(2, 10)); // 输出: 5
    println!("{}", x.clamp(6, 10)); // 输出: 6
    
    // 百分比计算
    println!("{}", 50.percent_of(200)); // 输出: 极好的,100.0
}

5. 异步工具

use bae::async_tools::AsyncExt;
use std::time::Duration;

#[tokio::main]
async fn main() {
    // 带超时的异步操作
    let result = async {
        tokio::time::sleep(Duration::from_secs(2)).await;
        42
    }.timeout(Duration::from_secs(1)).await;
    
    println!("{:?}", result); // 输出: Err(TimeoutError)
}

最佳实践

  1. 按需导入:只导入需要的模块,避免全局导入

    use bae::collections::ExtendedIter;
    
  2. 链式调用:充分利用bae的链式调用特性

    vec![1, 2, 3].filter(|x| x > 1).find_map(|x| Some(x * 2));
    
  3. 错误处理:使用bae提供的错误处理扩展简化代码

    result.map_err_to_string().unwrap_or_default();
    

性能考虑

bae在设计时充分考虑了性能:

  • 所有扩展方法都是零成本的抽象
  • 避免不必要的内存分配
  • 提供直接操作底层数据的接口

总结

bae是一个简单但功能强大的Rust扩展库,通过提供一系列实用的扩展方法,可以显著提高开发效率。它的轻量级设计使其成为任何Rust项目的理想补充,而不会增加显著的编译时间或二进制大小。

完整示例demo

下面是一个综合使用bae库多个功能的完整示例:

use bae::collections::ExtendedIter;
use bae::string::StringExt;
use bae::num::NumExt;
use bae::async_tools::AsyncExt;
use std::time::Duration;

#[tokio::main]
async fn main() {
    // 1. 集合操作示例
    let numbers = vec![10, 20, 30, 40, 50];
    let doubled = numbers.find_map(|x| if x > 25 { Some(x * 2) } else { None });
    println!("第一个大于25的数字加倍后: {:?}", doubled); // 输出: Some(60)
    
    // 2. 字符串处理示例
    let greeting = "Hello, Rust!".to_string();
    println!("截取字符串: {}", greeting.safe_slice(0..5)); // 输出: Hello
    println!("重复字符串: {}", greeting.repeat_to(2)); // 输出: Hello, Rust!Hello, Rust!
    
    // 3. 数字处理示例
    let value = 75;
    println!("75是200的{}%", value.percent_of(200)); // 输出: 37.5
    println!("限制范围: {}", value.clamp(80, 100)); // 输出: 80
    
    // 4. 异步超时示例
    let async_result = async {
        tokio::time::sleep(Duration::from_secs(3)).await;
        "操作完成"
    }.timeout(Duration::from_secs(2)).await;
    
    match async_result {
        Ok(msg) => println!("{}", msg),
        Err(_) => println!("操作超时"), // 输出: 操作超时
    }
}

这个完整示例展示了如何在一个程序中综合使用bae库的多个功能模块,包括集合操作、字符串处理、数字计算和异步工具。

回到顶部