2 个版本
| 0.1.1 | 2024 年 8 月 1 日 |
|---|---|
| 0.1.0 | 2024 年 8 月 1 日 |
| 0.0.1 |
|
#2219 in 异步
每月 331 次下载
在 2 crates 中使用
11KB
96 行代码
Rust 宏,用于统一同步和异步代码库
async/await 机制已成为处理 I/O 绑定应用程序异步编程的有用工具。然而,它引入了一个重大挑战:异步代码是“传染性的”,意味着不能在同步环境中使用。因此,创建库的开发者必须提供两种实现:同步和异步。异步实现中很大一部分不需要并发,最终变得冗余,使用略微不同的语法描述了完全相同的逻辑。
此库提供了两个宏,#[_async] 和 _await!(...),以解决必须在同步和异步版本中存在的非并发代码的管理问题。这些宏允许您注释此类代码,库将自动生成同步和异步版本。例如,以下代码
use build_async::*;
#[_async]
fn foo() {
_await!(boo());
_await!(x.zoo());
}
将展开为
fn foo() {
boo();
x.zoo();
}
async fn foo_async() {
boo_async().await;
x.zoo_async().await;
}
#[_async] 宏可以应用于任何非异步函数或方法定义,无论是否在 impl 或 trait 定义内部。此宏生成函数的同步和异步版本。_await!(...) 宏可以应用于带有 #[_async] 的函数或方法定义中的显式函数或方法调用。根据上下文(同步或异步),_await!(...) 扩展为同步调用或使用 await 的异步调用。为了避免名称冲突,此机制生成的异步版本名称被赋予后缀 _async。
这是一个更全面的例子,展示了如何在 trait 和 impl 定义中使用这些宏。该示例还展示了它们如何与同步和异步特性和类型集成,即使不遵循 _async 命名约定。
use build_async::*;
trait Writer {
type Error;
#[_async]
fn write(&mut self, bytes: &[u8]) -> Result<usize, Self::Error> {
unimplemented!()
}
}
impl<T: std::io::Write> Writer for T {
type Error = std::io::Error;
fn write(&mut self, bytes: &[u8]) -> Result<usize, Self::Error> {
self.write(self, bytes)
}
}
impl<T: tokio::io::AsyncWriteExt> Writer for T {
type Error = tokio::io::Error;
async fn write_async(&mut self, bytes: &[u8]) -> Result<usize, Self::Error> {
self.write(self, bytes).await
}
}
trait Encoder {
type Error;
#[_async]
fn encode_bool(&mut self, value: &bool) -> Result<(), Self::Error> {
_await!(self.encode_u8(&(*value).into()))
}
...
}
trait Encode {
#[_async]
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), E::Error>;
}
impl<T: Encode> Encode for Box<T> {
#[_async]
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> {
_await!(T::encode(self, encoder))?;
Ok(())
}
}
_await 宏假设它所应用的功能既有同步版本也有异步版本,其中异步版本是异步的,并且仅通过 _async 后缀在名称上有所不同。如果现有代码库中不遵循这些约定,可以实现如 Writer 之类的适配器来弥合差距。
有关实际示例,请参阅 crate cerdito 和 rustbif。
最后,关于这个库的一个特殊细节:我们建议使用 use build_async::*; 隐式导入宏。否则,显式导入语句将如下所示:use build_async::{_async, _await_sync, _await_async}; 这可能会令人困惑,因为它提出了诸如“_await 在哪里?”和“为什么我需要导入 _await_sync 和 _await_async?”等问题。原因是 _await 是一个“伪宏”。它看起来和感觉像一个宏,但它从未被定义过。当 _async 宏遇到 _await 时,它会根据上下文将其替换为 _await_sync 或 _await_async。
依赖关系
~260–710KB
~17K SLoC