Rust 如何将特殊的NotReady逻辑添加到tokio io?

Rust 如何将特殊的NotReady逻辑添加到tokio io?,rust,future,rust-tokio,Rust,Future,Rust Tokio,我正在尝试创建一个流,它将等待特定字符进入缓冲区。我知道在BufRead上有read_until(),但实际上我需要一个自定义解决方案,因为这是实现等待缓冲区中某个特定字符串(或者,例如,发生regexp匹配)的垫脚石 在我第一次遇到这个问题的项目中,问题是当我从内部future获取一个Ready(41;并从函数返回NotReady时,未来处理就挂起了。我发现我不应该那样做(最后一段)。然而,我没有得到的是,那一段中承诺的实际替代方案是什么。我阅读了东京网站上所有已发表的文件,目前对我来说没有任

我正在尝试创建一个
,它将等待特定字符进入缓冲区。我知道在
BufRead
上有
read_until()
,但实际上我需要一个自定义解决方案,因为这是实现等待缓冲区中某个特定字符串(或者,例如,发生regexp匹配)的垫脚石

在我第一次遇到这个问题的项目中,问题是当我从内部future获取一个
Ready(41;
并从函数返回
NotReady
时,未来处理就挂起了。我发现我不应该那样做(最后一段)。然而,我没有得到的是,那一段中承诺的实际替代方案是什么。我阅读了东京网站上所有已发表的文件,目前对我来说没有任何意义

下面是我当前的代码。不幸的是,我不能使它更简单和更小,因为它已经坏了。目前的结果是:

Err(Custom { kind: Other, error: Error(Shutdown) })
Err(Custom { kind: Other, error: Error(Shutdown) })
Err(Custom { kind: Other, error: Error(Shutdown) })
<ad infinum>

.

如果需要更多数据,您需要再次调用
poll\u read
,直到找到您要查找的内容或
poll\u read
返回
NotReady

您可能希望避免在一个任务中循环太长时间,因此如果
poll\u read
没有返回
NotReady
,您可以构建一个
yield\u task
函数来调用;它确保在运行其他挂起的任务后尽快再次调用您的任务

要使用它,只需运行
returnyield_task()

fn屈服内部(){
使用期货::任务;
任务::当前().notify();
}
#[在线(始终)]
pub fn yield_task()->Poll{
屈服内部();
Ok(异步::NotReady)
}
另见


随着新的async/await API的推出,futures::task::current
消失了;相反,您需要一个引用,它作为新trait方法的参数提供

如果您已经手动实现该特性,只需插入:

context.waker().wake_by_ref();
return std::task::Poll::Pending;
或者自己构建一个实现类型,只产生一次:

pub struct Yield {
    ready: bool,
}

impl core::future::Future for Yield {
    type Output = ();

    fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> {
        let this = self.get_mut();
        if this.ready {
            core::task::Poll::Ready(())
        } else {
            cx.waker().wake_by_ref();
            this.ready = true; // ready next round
            core::task::Poll::Pending
        }
    }
}

pub fn yield_task() -> Yield {
    Yield { ready: false }
}
pub struct Yield {
    ready: bool,
}

impl core::future::Future for Yield {
    type Output = ();

    fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> {
        let this = self.get_mut();
        if this.ready {
            core::task::Poll::Ready(())
        } else {
            cx.waker().wake_by_ref();
            this.ready = true; // ready next round
            core::task::Poll::Pending
        }
    }
}

pub fn yield_task() -> Yield {
    Yield { ready: false }
}
yield_task().await;