#async #iterator #generator #stable #sink #convert #function

async_to_iter

将异步函数转换为稳定 Rust 上的生成器

1 个不稳定版本

0.1.0 2024 年 8 月 16 日

#1068算法

Download history 64/week @ 2024-08-10

每月 64 次下载

MIT/Apache

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和一个全局分配器。

无运行时依赖