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