[英]In async Rust, how to I implement a wrapper around poll?
Suppose I have an async function foo
that returns some value.假设我有一个异步 function foo
返回一些值。 The value returned is different after each call (this could be eg something that reads chunks of data from a file or a random number generator).每次调用后返回的值都不同(例如,这可能是从文件或随机数生成器中读取数据块的东西)。
I want to implement a wrapper struct around foo
that implements AsyncRead
.我想在foo
周围实现一个实现AsyncRead
的包装器结构。 The wrapper reads the values from foo
, processes them in some way, and then places them into the user-supplied buffer.包装器从foo
读取值,以某种方式处理它们,然后将它们放入用户提供的缓冲区中。
Here's what I've tried:这是我尝试过的:
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,
}
}
}
This obviously doesn't compile because poll()
wants a pinned value.这显然不能编译,因为poll()
想要一个固定值。 Now, how do I pin the future returned by foo
?现在,我如何固定foo
返回的未来? I tried various combinations of Box::pin
, Pin::new
and pin_mut!
我尝试了Box::pin
、 Pin::new
和pin_mut!
but none of them worked.但他们都没有工作。
Also, am I supposed to store the Future
in my struct FooReader
until it's ready?另外,我是否应该将Future
存储在我的 struct FooReader
中,直到它准备好? Or am I free to drop it after each call, even if it's pending?或者我是否可以在每次通话后随意放弃它,即使它正在等待处理?
EDIT: The following works:编辑:以下作品:
let mut future: Pin<Box<dyn Future<Output = u8>>> = Box::pin(foo());
match future.as_mut().poll(ctx) {
...
}
For some reason I have to give future
an explicit type annotation, otherwise it doesn't compile (somehow the compiler is making confusion between impl Future
and dyn Future
).出于某种原因,我必须给future
一个明确的类型注释,否则它不会编译(编译器不知何故混淆了impl Future
和dyn Future
)。
Even if it works, I would still like to know if this is the "official" way to do it.即使它有效,我仍然想知道这是否是“官方”的方式。
For some reason, the Future
trait is not in the standard prelude, so you have to use
it before calling the function (the hint is there, buried between all the other compiler errors):出于某种原因, Future
特征不在标准前奏中,因此您必须在调用 function 之前use
它(提示就在那里,隐藏在所有其他编译器错误之间):
use std::future::Future;
Then, yes, you must pin the future before use.那么,是的,您必须在使用前固定未来。 The easiest way in your case is with pin_mut!
在您的情况下,最简单的方法是使用pin_mut!
, that uses a funny syntax: ,它使用了一个有趣的语法:
let f = foo();
pin_mut!(f);
Now, you can call poll()
, but remember that you must forward your Context
argument:现在,您可以调用poll()
,但请记住您必须转发Context
参数:
match f.poll(ctx) {
Playground with working code.带有工作代码的游乐场。
About storing the future or dropping it, you can do whatever you want, that depends on the exact semantics.关于存储未来或丢弃它,你可以做任何你想做的事情,这取决于确切的语义。 I personally would expect you to keep the future and run it to completion unless there is something in the documentation that explicitly says otherwise.我个人希望您保留未来并将其运行到完成,除非文档中有明确说明的内容。
Naturally, if you store the future in your struct, pin_mut!
当然,如果你将未来存储在你的结构中, pin_mut!
will not work because it consumes its argument.将不起作用,因为它消耗了它的论点。 You need to either keep it in a Pin<Box>
, or project the pin from self
, since it is already pinned.您需要将其保存在Pin<Box>
中,或者从self
中投射引脚,因为它已经被固定了。
To keep the Pin<Box>
you do something like:要保留Pin<Box>
,您可以执行以下操作:
pub struct FooReader {
f: Option<Pin<Box<dyn Future<Output=u8>>>>,
}
And then to use it do not forget the Box::as_mut()
since you need a Pin<&mut Future>
, not a Pin<Box<impl Future>>
:然后使用它不要忘记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) {
You'll probably want to check self.f
before calling foo()
again, but you get the idea.您可能想在再次调用foo()
之前检查self.f
,但您明白了。
The option of the pin projection is nicer because you avoid the extra allocation for the Box , but it is more complex and requires extra crates or a bit of unsafe code. pin 投影的选项更好,因为您避免了Box的额外分配,但它更复杂并且需要额外的 crate 或一些不安全的代码。 If you are really interested I think it deserves a new question on its own.如果您真的感兴趣,我认为它本身值得提出一个新问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.