在async Rust中,如何实现一个围绕poll的包装器?

问题描述 投票:1回答:1

假设我有一个异步函数 foo 返回一些值。每次调用后返回的值都是不同的(例如,可以是从文件中读取数据块或随机数生成器)。

我想实现一个围绕 foo 实现 AsyncRead. 包装器从 foo,以某种方式处理它们,然后将它们放入用户提供的缓冲区。

这是我试过的。

use futures::io::AsyncRead;
use pin_utils::pin_mut;
use std::io;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;

async fn foo() -> u8 {
    b'x'
}

pub struct FooReader;

impl AsyncRead for FooReader {
    fn poll_read(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8])
        -> Poll<io::Result<usize>> 
    {
        if buf.is_empty() {
            return Poll::Ready(Ok(0));
        }
        match foo().poll() {  // << problem here
            Poll::Ready(byte) => {
                buf[0] = byte;
                Poll::Ready(Ok(1))
            },
            Poll::Pending => Poll::Pending,
        }
    }
}

(Link to Playground)

这显然不能编译,因为 poll() 想要一个寄托的价值。现在。我如何将未来归来的 foo? 我试过各种组合 Box::pin, Pin::newpin_mut! 但都没有用。

还有 我应该存储的是 Future 在我的结构中 FooReader 直到它准备好了? 还是说我每次打完电话后,即使是待处理,也可以自由放弃?


EDIT: 下面的工作。

let mut future: Pin<Box<dyn Future<Output = u8>>> = Box::pin(foo());
match future.as_mut().poll(ctx) {
    ...
}

(Link to Playground)

出于某种原因,我必须给 future 的类型注解,否则就不能编译(不知为何,编译器会混淆了 impl Futuredyn Future).

即使可行,我还是想知道这是否是 "官方 "的做法。

asynchronous rust async-await future
1个回答
0
投票

由于某些原因,在调用函数foo后,返回的 Future 特质不在标准的前奏中,所以你必须要有 use (提示就在那里,埋在所有其他编译器错误之间)。

use std::future::Future;

那么,是的,你必须在使用前锁定未来。在你的例子中,最简单的方法是用 pin_mut!,它使用了一个有趣的语法。

let f = foo();
pin_mut!(f);

现在,你可以调用 poll()但请记住,你必须转发你的 Context 争论。

match f.poll(ctx) {

游乐场 与工作代码。

关于存储未来或放弃未来,你可以做任何你想做的事情,这取决于具体的语义。我个人希望你能保留未来,并将其运行到完成,除非文档中有其他明确的规定。

当然,如果你把未来存储在你的struct.C中,那么你就可以把未来存储在你的struct.C中。pin_mut! 将无法工作,因为它消耗了它的参数。你需要把它放在一个 Pin<Box>计划 销子 self,因为它已经被钉住了。

为了保持 Pin<Box> 你做的事情一样。

pub struct FooReader {
    f: Option<Pin<Box<dyn Future<Output=u8>>>>,
}

然后使用它不要忘记 Box::as_mut() 因为你需要一个 Pin<&mut Future>,不是 Pin<Box<impl Future>>:

        let f = foo();
        self.f = Some(Box::pin(f)); //remember to declare (mut self) above!
        match self.f.as_mut().unwrap().as_mut().poll(ctx) {

你可能要检查 self.f 呼叫前 foo() 再次,但你懂的。

的选择。凸针 是比较好的,因为你避免了额外的分配给 盒子但它更复杂,需要额外的箱子或一点不安全的代码。如果你真的有兴趣,我认为它值得单独提出一个新问题。

© www.soinside.com 2019 - 2024. All rights reserved.