1 个不稳定版本
新 0.1.0 | 2024 年 8 月 16 日 |
---|
#1068 在 算法
每月 64 次下载
12KB
178 行
将异步函数转换为稳定 Rust 上的生成器
此软件包允许编写类似生成器的 async
代码,以在今天的 (2024 年 8 月) 稳定 Rust 上实现 Iterator
。
许可证
此软件包根据 Apache 2.0 和 MIT 许可证的条款进行双重许可。
使用示例
use async_to_iter::{IterSink, make_iter};
// Async code that implements the iterator.
async fn count_to_impl(sink: IterSink<u32>, n: u32) {
for i in 1..=n {
sink.yield_value(i).await;
}
}
// Function that constructs the iterator from async code using `make_iter()`.
fn count_to(n: u32) -> impl Iterator<Item = u32> {
make_iter(move |sink| count_to_impl(sink, n))
}
fn main() {
// The resulting iterator can be accessed as usual.
let mut iter = count_to(3);
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), None);
}
常见问题解答
这是怎么工作的?
编译器自动将异步代码转换为在 await
点保存其内部状态的有限状态机。这就是 Rust 中异步代码长期以来是如何实现的。 make_iter
返回一个实现 Iterator
的类型,该类型将 Iterator::next()
转换为 Future::poll()
调用。
在 yield 点产生值和挂起未来的实现是通过 IterSink::yield_value()
。它保存异步代码提供的值(它稍后将从 Iterator::next()
返回)并返回一个 Future
,该 Future
在第二次调用 Future::poll
时准备好。这样,每次产生值时,异步代码的执行就暂停一次。
这个软件包使用 unsafe
吗?
它只用于一件事情:创建一个无操作 Waker
。它是安全的,因为无操作唤醒器什么都不做,并且它实际上重新实现了标准库中的不稳定 安全 函数:Waker::noop()
。这个crate的其余部分只使用安全的Rust代码。
这是一个零成本的抽象吗?
不幸的是,不是。产生迭代器输出值的future存储在堆上——这是必要的,以便在不影响由make_iter()
返回的Iterator
实现的可使用性的情况下固定它。这也会导致一些其他的分配。未来可能会优化分配的数量,但这个抽象成为零成本的抽象的可能性不大。
如果你需要在Rust中使用零成本的生成器,你可能会不得不使用一些Nightly特性。
这在#[no_std]
环境中工作吗?
是的,这个crate是#[no_std]
。但是,它需要alloc
crate和一个全局分配器。