I am attempting to create a struct that will allow someone to call .shutdown()
, which will resolve a future (that is otherwise pending). It can only be called once. In the implementation of the Future
trait, I receive an error that poll
is not defined, despite it being present in the documentation (under impl Future
).
Though I am using std::future::Future
as the impl
, I tried adding use futures::prelude::*
, which would bring the preview trait into scope. Both RLS and rustc inform me that the import is unused, so that's not the issue.
Note that I am not using a simple boolean flag, as I intend for this to be able to be callable from any thread — that's an implementation detail that is irrelevant here.
use futures::channel::oneshot; // [email protected]
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
pub struct ShutdownHandle {
sender: oneshot::Sender<()>,
receiver: oneshot::Receiver<()>,
}
impl ShutdownHandle {
pub fn new() -> Self {
let (sender, receiver) = oneshot::channel();
Self { sender, receiver }
}
pub fn shutdown(self) -> Result<(), ()> {
self.sender.send(())
}
}
impl Future for ShutdownHandle {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.receiver.poll(&mut cx).map(|_| ())
}
}
fn main() {
let runner = ShutdownHandle::new();
assert!(runner.shutdown().is_ok());
}
I receive the following error:
error[E0599]: no method named `poll` found for type `futures_channel::oneshot::Receiver<()>` in the current scope
--> src/main.rs:28:23
|
28 | self.receiver.poll(&mut cx).map(|_| ())
| ^^^^
What am I missing? Surely there's some way to "pass through" the polling. I am using nightly (2019-07-18).
It's true, Receiver
does not implement Future
; only Pin<&mut Receiver>
does. You need to project the pinning from your type to the field.
Unpin
impl Future for ShutdownHandle {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
// I copied this code from Stack Overflow without reading the text that
// told me how to verify that this code uses `unsafe` correctly.
unsafe { self.map_unchecked_mut(|s| &mut s.receiver) }.poll(cx).map(|_| ())
}
}
You must read the pin
module to thoroughly understand the requirements to use unsafe
here.
I like to use a helper library, such as pin_project, to handle more complicated types of projection:
#[unsafe_project(Unpin)]
pub struct ShutdownHandle {
#[pin]
sender: oneshot::Sender<()>,
#[pin]
receiver: oneshot::Receiver<()>,
}
impl Future for ShutdownHandle {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.project();
this.receiver.poll(cx).map(|_| ())
}
}
Unpin
Ömer Erden points out that the futures-preview crate provides FutureExt::poll_unpin
. This method takes a mutable reference to a type that implements Unpin
and creates a brand new Pin
with it.
Since oneshot::Receiver
does implement Unpin
, this can be used here:
impl Future for ShutdownHandle {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.receiver.poll_unpin(cx).map(|_| ())
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With