在调用异步FNS时创建值流?

时间:2019-06-22 23:51:38

标签: async-await rust

我不知道如何提供结构(或不提供)Stream,其中我await的异步函数来获取流的值所需的数据。

我尝试直接实现Stream特质,但是遇到问题,因为我想使用诸如await ing之类的异步方法,编译器不希望我调用异步方法功能。

我假设我缺少有关此Stream库的目标的背景知识,而我只是在错误地进行攻击,也许我根本不应该关注Stream,但我不知道还有什么地方可以转。我已经在Stream模块中看到其他functions可能有用,但是我不确定如何存储任何状态并使用这些功能。

作为我实际目标的略微简化版本,假设我想从AsyncRead对象提供64字节vecs流(即tcp流),但还要在逻辑最终产生值的任何逻辑内部存储一点状态。流,在此示例中为计数器。

pub struct Receiver<T> where T: AsyncRead + Unpin {
    readme: T,
    num: u64,
}

// ..code for a simple `new() -> Self` function..

impl<T> Stream for Receiver<T> where T: AsyncRead + Unpin {
    type Item = Result<Vec<u8>, io::Error>;

    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Self::Item>> {
        let mut buf : [u8; 64] = [0; 64];
        match self.readme.read_exact(&mut buf).await {
            Ok(()) => {
                self.num += 1;
                Poll::Ready(Some(Ok(buf.to_vec())))
            }
            Err(e) => Poll::Ready(Some(Err(e)))
        }
    }
}

这无法建立,说

error[E0728]: `await` is only allowed inside `async` functions and blocks

感谢您的帮助!


编辑:

我正在使用rustc 1.36.0-nightly (d35181ad8 2019-05-20),而我的Cargo.toml看起来像这样:

[dependencies]
futures-preview = { version = "0.3.0-alpha.16", features = ["compat", "io-compat"] }
pin-utils = "0.1.0-alpha.4"

2 个答案:

答案 0 :(得分:0)

由用户reddit postMatthias247答复/粘贴:

  

不幸的是,目前无法实现-流必须手动实现,并且不能使用异步fn。将来是否有可能改变这一点尚不清楚。

     

您可以通过定义不同的Stream特性来解决此问题,该特性利用Future之类的方法:

trait Stream<T> { 
   type NextFuture: Future<Output=T>;

   fn next(&mut self) -> Self::NextFuture; 
}
     

This articlethis futures-rs issue周围有更多信息。

答案 1 :(得分:0)

您可以使用gen-stream条板箱进行此操作:

#![feature(generators, generator_trait, gen_future)]

use {
    futures::prelude::*,
    gen_stream::{gen_await, GenTryStream},
    pin_utils::unsafe_pinned,
    std::{
        io,
        marker::PhantomData,
        pin::Pin,
        sync::{
            atomic::{AtomicU64, Ordering},
            Arc,
        },
        task::{Context, Poll},
    },
};

pub type Inner = Pin<Box<dyn Stream<Item = Result<Vec<u8>, io::Error>> + Send>>;

pub struct Receiver<T> {
    inner: Inner,
    pub num: Arc<AtomicU64>,
    _marker: PhantomData<T>,
}

impl<T> Receiver<T> {
    unsafe_pinned!(inner: Inner);
}

impl<T> From<T> for Receiver<T>
where
    T: AsyncRead + Unpin + Send + 'static,
{
    fn from(mut readme: T) -> Self {
        let num = Arc::new(AtomicU64::new(0));

        Self {
            inner: Box::pin(GenTryStream::from({
                let num = num.clone();
                static move || loop {
                    let mut buf: [u8; 64] = [0; 64];
                    match gen_await!(readme.read_exact(&mut buf)) {
                        Ok(()) => {
                            num.fetch_add(1, Ordering::Relaxed);
                            yield Poll::Ready(buf.to_vec())
                        }
                        Err(e) => return Err(e),
                    }
                }
            })),
            num,
            _marker: PhantomData,
        }
    }
}

impl<T> Stream for Receiver<T>
where
    T: AsyncRead + Unpin,
{
    type Item = Result<Vec<u8>, io::Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        self.inner().poll_next(cx)
    }
}