我不知道如何提供结构(或不提供)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"
答案 0 :(得分:0)
由用户reddit post从Matthias247答复/粘贴:
不幸的是,目前无法实现-流必须手动实现,并且不能使用异步fn。将来是否有可能改变这一点尚不清楚。
您可以通过定义不同的Stream特性来解决此问题,该特性利用Future之类的方法:
trait Stream<T> { type NextFuture: Future<Output=T>; fn next(&mut self) -> Self::NextFuture; }
This article和this 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)
}
}