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

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

基本使用

Align<N>是一个零大小类型(zero-sized type),其对齐方式等于N:

use elain::Align;
use core::mem::{align_of, align_of_val};

// 测试不同对齐值的Align类型
assert_eq!(align_of::<Align<1>>(), 1);
assert_eq!(align_of::<Align<2>>(), 2);
assert_eq!(align_of::<Align<4>>(), 4);

const FOO_ALIGN: usize = 8;

// 使用Align强制结构体对齐
#[repr(C)]
struct Foo {
    _align: Align<FOO_ALIGN>,
}

let foo: Foo = Foo { _align: Align::NEW };

// 验证结构体对齐
assert_eq!(align_of_val(&foo), 8);

有效的对齐值必须是2的幂次方且小于等于2^28。提供无效的对齐值会导致类型错误:

use elain::Align;

struct Foo(Align<3>); // 编译错误:3不是有效的对齐值

泛型使用

因为只有部分整数是有效的对齐值,所以在泛型中提供类型的对齐需要额外的工作:

use elain::Align;

struct Foo<const N: usize> {
    _align: Align<N>,
}

要解决这个错误,可以添加一个where约束,使用Alignment特性来检查Align<N>是否有效:

use elain::{Align, Alignment};
use core::mem::align_of;

// 泛型结构体,使用Align强制对齐
struct Foo<const MIN_ALIGNMENT: usize>
where
    Align<MIN_ALIGNMENT>: Alignment
{
    _align: Align<MIN_ALIGNMENT>,
    bar: u8,
    baz: u16,
}

// 测试不同对齐值
assert_eq!(align_of::<Foo<1>>(), 2);  // 实际对齐为字段baz的对齐
assert_eq!(align_of::<Foo<2>>(), 2);
assert_eq!(align_of::<Foo<4>>(), 4);

完整示例代码

下面是一个完整的示例,展示了elain库的基本和高级用法:

use elain::{Align, Alignment};
use core::mem::{align_of, align_of_val};

fn main() {
    // 基本使用示例
    println!("Align<1> alignment: {}", align_of::<Align<1>>());
    println!("Align<2> alignment: {}", align_of::<Align<2>>());
    println!("Align<4> alignment: {}", align_of::<Align<4>>());

    // 结构体对齐示例
    const CUSTOM_ALIGN: usize = 16;
    
    #[repr(C)]
    struct CustomAligned {
        _align: Align<CUSTOM_ALIGN>,  // 强制16字节对齐
        data: [u8; 32],              // 32字节数据
    }
    
    let custom = CustomAligned {
        _align: Align::NEW,
        data: [0; 32],
    };
    
    println!("CustomAligned alignment: {}", align_of_val(&custom));
    
    // 泛型使用示例
    print_alignment::<1>();  // 1字节对齐
    print_alignment::<2>();  // 2字节对齐
    print_alignment::<4>();  // 4字节对齐
    print_alignment::<8>();  // 8字节对齐
}

// 泛型函数示例,展示如何在不同对齐下工作
fn print_alignment<const A: usize>()
where
    Align<A>: Alignment,
{
    #[repr(C)]
    struct GenericAligned<const A: usize>
    where
        Align<A>: Alignment,
    {
        _align: Align<A>,  // 泛型对齐
        value: u32,       // 示例字段
    }
    
    let aligned = GenericAligned::<A> {
        _align: Align::NEW,
        value: 42,
    };
    
    println!("GenericAligned<{}> alignment: {}", A, align_of_val(&aligned));
}

安装

要将elain添加到您的项目中,可以在项目目录中运行以下Cargo命令:

cargo add elain

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

elain = "0.3.1"

许可证

elain库采用MIT或Apache-2.0双重许可证。


1 回复

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

介绍

elain是一个轻量级的Rust工具库,旨在为Rust开发者提供一组高效、实用的功能扩展。它专注于提供那些Rust标准库中没有但实际开发中经常需要的功能,帮助开发者提高生产力。

elain的主要特点包括:

  • 极简设计,无额外依赖
  • 零成本抽象
  • 线程安全
  • 良好的文档和测试覆盖率

安装

在Cargo.toml中添加依赖:

[dependencies]
elain = "0.3.0"  # 请使用最新版本

主要功能及使用示例

1. 集合操作增强

use elain::collections::{ExtendedVec, ExtendedHashMap};

fn main() {
    // Vec扩展
    let mut vec = vec![1, 2, 3, 4, 5];
    
    // 安全交换移除(不保留顺序但O(1)复杂度)
    let removed = vec.swap_remove_if(|&x| x == 3);
    println!("移除的元素: {:?}", removed); // Some(3)
    println!("剩余向量: {:?}", vec); // [1, 2, 5, 4]
    
    // HashMap扩展
    use std::collections::HashMap;
    let mut map = HashMap::new();
    map.insert("a", 1);
    map.insert("b", 2);
    
    // 安全地获取并修改值
    map.update("a", |v| *v += 10);
    println!("更新后的值: {:?}", map.get("a")); // Some(11)
}

2. 错误处理增强

use elain::error::{ErrorExt, ResultExt};

fn parse_number(s: &str) -> Result<i32, std::num::ParseIntError> {
    s.parse::<i32>()
}

fn main() {
    // 错误链式处理
    let result = parse_number("123a")
        .map_err_to_str()  // 将错误转换为字符串
        .context("解析数字失败");  // 添加上下文
        
    match result {
        Ok(n) => println!("数字: {}", n),
        Err(e) => println!("错误: {}", e), // "解析数字失败: invalid digit found in string"
    }
    
    // 可选的结果快速处理
    let opt: Option<i32> = Some(42);
    let res = opt.ok_or_else(|| "缺少值".to_string());
    println!("{:?}", res); // Ok(42)
}

3. 字符串处理

use elain::string::StringExt;

fn main() {
    let s = "hello world";
    
    // 安全地获取子字符串
    println!("{}", s.try_substring(0, 5).unwrap()); // "hello"
    
    // 驼峰命名转换
    println!("{}", s.to_camel_case()); // "helloWorld"
    
    // 字符串填充
    println!("{:>10}", s.left_pad(' ', 15); // "    hello world"
}

4. 迭代器增强

use elain::iter::IteratorExt;

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    // 带索引的map
    let squared: Vec<_> = numbers.iter()
        .enumerate_map(|i, &x| x * (i as i32 + 1))
        .collect();
    println!("{:?}", squared); // [1, 4, 9, 16, 25]
    
    // 分组迭代
    let groups: Vec<_> = numbers.iter()
        .group_by(|&&x| x % 2 == 0)
        .collect();
    println!("{:?}", groups); // [(false, [1, 3, 5]), (true, [2, 4])]
}

5. 异步工具

use elain::async_utils::{AsyncExt, timeout};
use std::time::Duration;

async fn long_running_task() -> i32 {
    tokio::time::sleep(Duration::from_secs(2)).await;
    42
}

#[tokio::main]
async fn main() {
    // 带超时的异步操作
    match timeout(Duration::from_secs(1), long_running_task()).await {
        Ok(result) => println!("结果: {}", result),
        Err(_) => println!("操作超时"),
    }
    
    // 异步重试机制
    let result = long_running_task()
        .retry(3, Duration::from_secs(1))
        .await;
    println!("最终结果: {:?}", result);
}

性能建议

  1. 对于热点代码路径,优先使用elain提供的_unchecked版本方法(在确认安全的情况下)
  2. 大量数据操作时,考虑使用elain提供的并行迭代器扩展
  3. 错误处理增强方法会引入少量额外开销,在性能关键路径慎用

总结

elain为Rust开发者提供了一组精心设计的实用工具,填补了标准库的一些空白。它的轻量级设计使其成为任何Rust项目的理想补充,而不会增加显著的编译时间或二进制大小负担。

完整示例demo

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

use elain::{collections::ExtendedVec, error::ResultExt, iter::IteratorExt, string::StringExt};
use std::collections::HashMap;

fn process_data(input: &str) -> Result<Vec<i32>, String> {
    // 字符串处理
    let trimmed = input.trim();
    if trimmed.is_empty() {
        return Err("输入为空".to_string());
    }

    // 安全子字符串
    let prefix = trimmed.try_substring(0, 5).unwrap_or("");

    // 转换为驼峰命名
    println!("处理前缀: {}", prefix.to_camel_case());

    // 模拟解析数据
    let numbers: Result<Vec<i32>, _> = trimmed
        .split(',')
        .map(|s| s.parse::<i32>().map_err_to_str().context("解析失败"))
        .collect();

    numbers
}

fn main() {
    // 集合操作
    let mut data = vec![10, 20, 30, 40, 50];
    data.swap_remove_if(|&x| x == 30);
    println!("处理后数据: {:?}", data);

    // 迭代器增强
    let processed: Vec<_> = data
        .iter()
        .enumerate_map(|i, &x| x * (i as i32 + 1))
        .collect();
    println!("带索引处理: {:?}", processed);

    // 错误处理增强
    match process_data(" 1,2,3,four,5 ") {
        Ok(nums) => {
            println!("解析结果: {:?}", nums);
            
            // HashMap操作
            let mut map = HashMap::new();
            for (i, &num) in nums.iter().enumerate() {
                map.insert(format!("key_{}", i), num);
            }
            
            map.update("key_0", |v| *v += 100);
            println!("更新后的map: {:?}", map);
        }
        Err(e) => println!("错误: {}", e),
    }
}

这个完整示例展示了:

  1. 字符串处理(修剪、子字符串、驼峰命名转换)
  2. 集合操作(安全交换移除)
  3. 迭代器增强(带索引的map)
  4. 错误处理增强(错误转换和添加上下文)
  5. HashMap操作(安全更新值)

输出示例可能如下:

处理前缀: 
处理后数据: [10, 20, 50, 40]
带索引处理: [10, 40, 150, 160]
错误: 解析失败: invalid digit found in string
回到顶部