#async #async-api #proc-macro #macro #maybe #future #api-version

maybe-async-cfg

根据您crate的功能统一同步和异步实现的进程宏

6个版本

0.2.4 2024年6月14日
0.2.3 2022年8月3日
0.2.1 2022年7月18日
0.2.0 2022年6月24日
0.1.1 2022年6月21日

#76 in 过程宏

Download history 509/week @ 2024-04-24 698/week @ 2024-05-01 1435/week @ 2024-05-08 1036/week @ 2024-05-15 583/week @ 2024-05-22 891/week @ 2024-05-29 523/week @ 2024-06-05 2276/week @ 2024-06-12 3953/week @ 2024-06-19 3034/week @ 2024-06-26 3737/week @ 2024-07-03 3517/week @ 2024-07-10 1537/week @ 2024-07-17 3773/week @ 2024-07-24 3796/week @ 2024-07-31 4133/week @ 2024-08-07

13,423每月下载量
18 个crate中使用 (17 直接)

MIT 许可证

145KB
2.5K SLoC

Maybe-Async-Cfg过程宏

为什么要在同步和异步代码中重复编写类似的代码呢?

Build Status MIT licensed Latest Version maybe-async

当在crate中实现API的同步和异步版本时,这两个版本的大多数API几乎相同,只是异步版本中包含一些异步/等待关键字。

maybe-async-cfg 通过 过程宏 帮助统一异步和同步实现。

  • 使用正常的 asyncawait 编写异步代码,当您需要阻塞代码时,让 maybe_async_cfg 处理那些 asyncawait
  • 添加 maybe 属性并指定基于功能的条件,根据这些条件生成同步或异步代码。
  • 如果需要,使用 only_if (或 remove_if) 保持指定版本的代码。

可以将 maybe 过程宏应用于以下代码

  • 使用声明
  • trait声明
  • trait实现
  • 函数定义
  • struct和enum定义
  • 模块

建议:在您的crate中启用 resolver ver2,这是Rust 1.51中引入的。如果不启用,则与具有冲突版本(一个异步和一个阻塞)的依赖项的crate可能会编译失败。

动机

异步/等待语言功能改变了Rust的异步世界。与map/and_then样式相比,现在的异步代码真的类似于同步版本代码。

在许多crate中,异步和同步版本的crate共享相同的API,但由于所有异步代码都必须等待,这阻止了异步和同步代码的统一。换句话说,我们被迫分别编写异步和同步实现。

宏的详细信息

要使用maybe-async-cfg,我们必须知道哪些代码块仅在同步实现中使用,哪些在异步中使用。这两个版本的实现应该共享相同的函数签名,除了async/await关键字。

使用maybe宏来处理在异步和同步版本中相同(除了async/await关键字)的代码。在宏参数中指定代码的异步和/或同步版本应该出现的条件(基于特性)。

  • 属性宏maybe

    提供了一种统一的方式,根据特性在需要时提供同步和异步转换,启用您的crate,并采用async first策略。

    [dependencies]
    maybe_async_cfg = "0.2"
    
    [features]
    use_sync = []
    use_async = []
    

    在此示例及所有后续示例中,我们使用两个特性。但您可以使用任何方便的条件,例如,将feature="use_sync"替换为not(feature="use_async")。请随意使用,maybe-async-cfg不会以任何方式分析条件,只是原样替换它们。

    在代码的不同版本(同步或异步)中需要更改的所有项之前添加maybe属性。

    想要保留异步代码?指定当您的代码应该是异步时的条件(基于特性)的async参数。

    想将异步代码转换为同步?指定生成同步代码时的条件sync参数。

    #[maybe_async_cfg::maybe(
        idents(Foo),
        sync(feature="use_sync"),
        async(feature="use_async")
    )]
    struct Struct {
        f: Foo,
    }
    

    转换后

    #[cfg(feature="use_sync")]
    struct StructSync {
        f: FooSync,
    }
    #[cfg(feature="use_async")]
    struct StructAsync {
        f: FooAsync,
    }
    
  • 过程宏content

    content宏允许您为许多maybe宏指定通用参数。在content宏内部使用所需的参数的default属性。

    maybe_async_cfg::content!{
    #![maybe_async_cfg::default(
        idents(Foo, Bar),
    )]
    
    #[maybe_async_cfg::maybe(
        sync(feature="use_sync"), 
        async(feature="use_async")
    )]
    struct Struct {
        f: Foo,
    }
    
    #[maybe_async_cfg::maybe(
        sync(feature="use_sync"), 
        async(feature="use_async")
    )]
    async fn func(b: Bar) {
        todo!()
    }
    } // content!
    

    转换后

    #[cfg(feature="use_sync")]
    struct StructSync {
        f: FooSync,
    }
    #[cfg(feature="use_async")]
    struct StructAsync {
        f: FooAsync,
    }
    
    #[cfg(feature="use_sync")]
    fn func_sync(b: BarSync) {
        todo!()
    }
    #[cfg(feature="use_async")]
    async fn func_async(b: BarAsync) {
        todo!()
    }
    

文档测试

在编写文档测试时,您可以标记它们仅适用于相应的代码版本。为此,在文档测试属性中指定only_if(VARIANT_KEY)。然后在其他所有代码版本中,此文档测试将被替换为空字符串。

#[maybe_async_cfg::maybe(
    idents(Foo),
    sync(feature="use_sync"),
    async(feature="use_async")
)]
/// This is a structure. 
/// ```rust, only_if(sync)
/// let s = StructSync{ f: FooSync::new() };
/// ```
/// ```rust, only_if(async)
/// let s = StructAsync{ f: FooAsync::new().await };
/// ```
struct Struct {
    f: Foo,
}

转换后

#[cfg(feature="use_sync")]
/// This is a structure. 
/// ```rust, only_if(sync)
/// let s = StructSync{ f: FooSync::new() };
/// ```
///
struct StructSync {
f: FooSync,
}
#[cfg(feature="use_async")]
/// This is a structure. 
///
/// ```rust, only_if(async)
/// let s = StructAsync{ f: FooAsync::new().await };
/// ```
struct StructAsync {
    f: FooAsync,
}

示例

服务客户端的rust实现

当实现任何服务的rust客户端时,例如awz3。异步和同步版本的API几乎相同,例如创建或删除存储桶、检索对象等。

示例service_clientmaybe-async-cfg可以真正让我们摆脱编写几乎相同的同步和异步代码的证明。当我们将maybe-async-cfg添加到依赖项时,可以通过添加is_sync特性门来在同步AWZ3客户端和异步客户端之间切换。

致谢

这个crate是基于以下这些优秀的crate重新设计的分支

谢谢!

许可证

MIT

依赖项

~1.2–1.7MB
~40K SLoC