Reputation: 53
I'm trying to create a DelayedValue
future that resolves to a value after a certain time period has elapsed. To do this I simply wanted to wrap the Sleep
future from tokio
crate. But I get errors relating to Pin
and no matter what I do I can't seem to call the poll
method on the underlying Sleep
member.
For reference here is a full program which fails to compile but should illustrate what I want:
use futures::task::{Context, Poll};
use futures::Future;
use std::pin::Pin;
use tokio::time::{sleep, Sleep, Duration};
struct DelayedValue<T> {
value: T,
sleep: Sleep,
}
impl<T> Future for DelayedValue<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match &mut self.sleep.poll(cx) {
Poll::Ready(()) => Poll::Ready(self.value),
x => x,
}
}
}
#[tokio::main]
async fn main() {
let dv = DelayedValue {
value: 10_u8,
sleep: sleep(Duration::from_millis(5000)),
};
println!("waiting for delayed value");
let v = dv.await;
println!("delayed value: {}", v);
}
There is also a playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d573d8dcbbef5c99314d98cacc3d6c92
Upvotes: 1
Views: 2368
Reputation: 23453
The easiest is probably to just map
the result of a Sleep
future instead of implementing a full new struct:
use futures::FutureExt;
use tokio::time::{ Duration, sleep };
#[tokio::main]
async fn main() {
let dv = sleep (Duration::from_millis (5000)).map (|_| { 10_u8 });
println!("waiting for delayed value");
let v = dv.await;
println!("delayed value: {}", v);
}
Upvotes: 0
Reputation: 53
For reference, since I only needed this for this struct I opted to not use pin-project
. Instead I implemented it myself for the field I needed:
#[derive(Debug)]
pub struct DelayedValue<T: Copy> {
value: T,
sleep: Sleep,
}
impl<T: Copy> DelayedValue<T> {
pub fn new(value: T, sleep: Sleep) -> DelayedValue<T> {
DelayedValue {value, sleep}
}
}
impl<T: Copy> Future for DelayedValue<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let x = self.value;
let s = unsafe { self.map_unchecked_mut(|s| &mut s.sleep) };
match &mut s.poll(cx) {
Poll::Ready(()) => Poll::Ready(x),
Poll::Pending => Poll::Pending,
}
}
}
Upvotes: 0
Reputation: 71535
The easiest way is to use pin-project
or pin-project-lite
:
pin_project_lite::pin_project! {
struct DelayedValue<T> {
value: Option<T>,
#[pin]
sleep: Sleep,
}
}
impl<T> Future for DelayedValue<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
match this.sleep.poll(cx) {
Poll::Ready(()) => Poll::Ready(this.value.take().unwrap()),
Poll::Pending => Poll::Pending,
}
}
}
Upvotes: 3