Rust轻量级异步宏库smol-macros的使用,简化异步编程与代码生成

Rust轻量级异步宏库smol-macros的使用,简化异步编程与代码生成

smol-macros是一个为smol-rs提供宏支持的库,它可以帮助快速搭建高效的异步运行时,简化异步编程。

简单执行器

使用main!宏可以轻松创建异步main函数:

use smol-macros::main;

main! {
    async fn main() {
        println!("Hello, world!");
    }
}

使用proc宏语法

如果更喜欢proc宏风格,可以使用macro_rules_attribute::apply

use macro_rules_attribute::apply;
use smol-macros::main;

#[apply(main!)]
async fn main() {
    println!("Hello, world!");
}

基于任务的执行器

当函数第一个参数是Executor时,会自动创建执行器:

use macro_rules_attribute::apply;
use smol-macros::{main, Executor};

#[apply(main!)]
async fn main(ex: &Executor<'_>) {
    ex.spawn(async { println!("Hello world!"); }).await;
}

使用线程安全的Executor会创建线程池,而LocalExecutor则不会创建线程。

测试

使用test!宏创建包含执行器的测试用例:

use macro_rules_attribute::apply;
use smol-macros::{test, Executor};

#[apply(test!)]
async fn do_test(ex: &Executor<'_>) {
    ex.spawn(async {
        assert_eq!(1 + 1, 2);
    }).await;
}

MSRV策略

最低支持的Rust版本是1.63。MSRV不会超过Debian Stable提供的Rust版本。

完整示例

以下是使用smol-macros的完整示例:

use smol-macros::{main, Executor};

// 简单异步main函数示例
main! {
    async fn main() {
        println!("Starting the async program...");
        
        // 使用执行器示例
        async_main().await;
    }
}

// 使用执行器的异步函数
async fn async_main() {
    let ex = Executor::new();
    
    // 创建多个异步任务
    let task1 = ex.spawn(async {
        println!("Task 1 running");
        1
    });
    
    let task2 = ex.spawn(async {
        println!("Task 2 running");
        2
    });
    
    // 等待任务完成
    let result1 = task1.await;
    let result2 = task2.await;
    
    println!("Results: {}, {}", result1, result2);
}

// 测试示例
#[cfg(test)]
mod tests {
    use super::*;
    use smol-macros::test;
    
    #[test]
    async fn test_async_addition() {
        let ex = Executor::new();
        
        let result = ex.spawn(async {
            1 + 1
        }).await;
        
        assert_eq!(result, 2);
    }
}

这个示例展示了:

  1. 使用main!宏创建异步main函数
  2. 使用执行器创建和管理异步任务
  3. 编写异步测试用例
  4. 任务间的await操作

要使用这个库,请在Cargo.toml中添加:

smol-macros = "0.1.1"

1 回复

Rust轻量级异步宏库smol-macros的使用

介绍

smol-macros 是一个轻量级的 Rust 异步宏库,旨在简化异步编程和代码生成。它基于 smol 异步运行时,提供了一组方便的宏来减少异步代码的样板代码量,使异步编程更加简洁和直观。

主要特性

  • 简化异步代码结构
  • 减少样板代码
  • 与 smol 运行时无缝集成
  • 轻量级且高效

安装

在 Cargo.toml 中添加依赖:

[dependencies]
smol-macros = "0.1"

使用方法

1. async!

简化异步块的创建:

use smol_macros::async;

fn main() {
    let task = async! {
        println!("Hello from async block!");
        42
    };
    
    let result = smol::block_on(task);
    println!("Result: {}", result);
}

2. spawn!

简化异步任务的生成:

use smol_macros::spawn;

fn main() {
    let handle = spawn! {
        println!("Running in spawned task");
        "Task completed"
    };
    
    let result = smol::block_on(handle);
    println!("{}", result);
}

3. select!

简化多个异步操作的选择:

use smol_macros::select;
use std::time::Duration;

async fn timeout() -> &'static str {
    smol::Timer::after(Duration::from_secs(2)).await;
    "timeout"
}

async fn computation() -> &'static str {
    smol::Timer::after(Duration::from_secs(1)).await;
    "computation"
}

fn main() {
    smol::block_on(async! {
        let result = select! {
            res = timeout() => res,
            res = computation() => res,
        };
        println!("First result: {}", result);
    });
}

4. try! 宏的异步版本

简化异步错误处理:

use smol_macros::try_async;

async fn might_fail(succeed: bool) -> Result<i32, &'static str> {
    if succeed {
        Ok(42)
    } else {
        Err("Something went wrong")
    }
}

fn main() {
    smol::block_on(async! {
        let result: i32 = try_async!(might_fail(true));
        println!("Result: {}", result);
        
        // 下面这行会提前返回错误
        let _ = try_async!(might_fail(false));
        println!("This won't be printed");
    });
}

高级用法

结合多个宏使用

use smol_macros::{async, spawn, select};

async fn task_one() -> &'static str {
    smol::Timer::after(std::time::Duration::from_secs(1)).await;
    "Task one completed"
}

async fn task_two() -> &'static str {
    smol::Timer::after(std::time::Duration::from_secs(2)).await;
    "Task two completed"
}

fn main() {
    let main_task = async! {
        let handle1 = spawn!(task_one());
        let handle2 = spawn!(task_two());
        
        select! {
            res = handle1 => println!("{}", res),
            res = handle2 => println!("{}", res),
        }
    };
    
    smol::block_on(main_task);
}

注意事项

  1. smol-macros 主要设计用于 smol 运行时,但也可以与其他兼容的运行时一起使用
  2. 宏展开后的代码可能会影响错误消息的可读性
  3. 在复杂场景下,直接使用原始 Future trait 可能更灵活

smol-macros 通过提供这些简洁的宏,显著减少了异步编程中的样板代码,使开发者能够更专注于业务逻辑而不是异步机制的低级细节。

完整示例代码

下面是一个综合使用smol-macros各种宏的完整示例:

use smol_macros::{async, spawn, select, try_async};
use std::time::Duration;

// 异步函数示例1:模拟网络请求
async fn fetch_data() -> Result<String, &'static str> {
    smol::Timer::after(Duration::from_secs(1)).await;
    Ok("Data fetched successfully".to_string())
}

// 异步函数示例2:模拟数据库查询
async fn query_database() -> Result<i32, &'static str> {
    smol::Timer::after(Duration::from_secs(2)).await;
    Ok(100)
}

// 异步函数示例3:模拟超时操作
async fn timeout_operation() -> &'static str {
    smol::Timer::after(Duration::from_secs(3)).await;
    "Operation timed out"
}

fn main() {
    // 使用async!宏创建主异步块
    let main_task = async! {
        // 使用spawn!宏并发执行多个任务
        let fetch_task = spawn!(fetch_data());
        let db_task = spawn!(query_database());
        let timeout_task = spawn!(timeout_operation());
        
        // 使用select!宏等待第一个完成的任务
        let first_result = select! {
            res = fetch_task => res.map(|s| format!("Fetch result: {}", s)),
            res = db_task => res.map(|n| format!("DB result: {}", n)),
            res = timeout_task => Ok(format!("Timeout: {}", res)),
        };
        
        // 使用try_async!宏处理可能错误的结果
        let result = try_async!(first_result);
        println!("First completed: {}", result);
        
        // 等待剩余任务完成
        let remaining_results = select! {
            res = fetch_task => res,
            res = db_task => res,
        };
        
        match remaining_results {
            Ok(res) => println!("Remaining result: {:?}", res),
            Err(e) => println!("Error: {}", e),
        }
    };
    
    // 使用smol运行时执行主任务
    smol::block_on(main_task);
}

代码说明

  1. 定义了三个异步函数模拟不同操作:

    • fetch_data(): 模拟网络请求,1秒后返回成功数据
    • query_database(): 模拟数据库查询,2秒后返回结果
    • timeout_operation(): 模拟超时操作,3秒后返回超时信息
  2. 主函数中使用async!宏创建主异步块

  3. 使用spawn!宏并发执行三个异步任务

  4. 使用select!宏选择最先完成的任务

  5. 使用try_async!宏处理可能错误的结果

  6. 最后处理剩余未完成的任务

这个示例展示了如何组合使用smol-macros提供的各种宏来构建复杂的异步逻辑,同时保持代码的简洁性和可读性。

回到顶部