Reputation: 121
I'm working on exercises from the Rust playground, and I'm stuck on implementing a Future for a structure. Here's how the task looks:
//Provide a Future trait implementation, transparently polling the inner_future,
// and printing its execution time in nanoseconds once it's ready.
// Using Fut: Unpin trait bound (or similar) is not allowed.
struct Measurable<Fut> {
inner_future: Fut,
started_at: Instant,
}
The task seems clear. We need to create a wrapper around Future and print its execution time. However, it's unclear what Fut is. I assumed it's a Future and drafted the following code:
use futures::executor::block_on;
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
time::Duration,
time::Instant,
};
#[derive(Debug)]
struct Measurable<Fut> {
inner_future: Fut,
started_at: Instant,
}
impl<Fut> Measurable<Fut> {
fn new(inner_future: Fut) -> Self {
MeasurableFuture {
inner_future,
started_at: Instant::now(),
}
}
}
impl<Fut: Future> Future for Measurable<Fut> {
type Output = Fut::Output;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
// move occurs because value has type `Fut`, which does not implement the `Copy` trait
let res = Poll::Ready(self.inner_future);
match res {
// syntax says that 'result' is a Fut, should i return Fut or Fut::Output?
Poll::Ready(result) => {
println!(
"Completed: {:?}",
Instant::now().checked_duration_since(self.started_at)
);
result
// Poll::Pending
}
Poll::Pending => Poll::Pending,
}
}
}
async fn hello_world() {
std::thread::sleep(Duration::from_secs(1));
println!("hello, world!");
}
fn main() {
let w = Measurable::new(hello_world());
let result = block_on(w);
println!("{:?}", result);
}
So there are two problems:
Move occurs because value has type Fut
, which does not implement the Copy
trait
res = Poll::Ready(self.inner_future);
I don't know what I should to return when task is ready
The question is, how do I correctly implement poll for this case, and what should I return? Maybe I misunderstood the task.
Upvotes: 3
Views: 963
Reputation: 71430
To create a Pin<&mut Field>
safely, you can use the pin-project
or pin-project-lite
crates:
pin_project_lite::pin_project! {
#[derive(Debug)]
struct Measurable<Fut> {
#[pin]
inner_future: Fut,
started_at: Instant,
}
}
impl<Fut: Future> Future for Measurable<Fut> {
type Output = Fut::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let res = this.inner_future.poll(cx);
match res {
Poll::Ready(result) => {
println!(
"Completed: {:?}",
Instant::now().checked_duration_since(*this.started_at)
);
Poll::Ready(result)
}
Poll::Pending => Poll::Pending,
}
}
}
You can also do that using unsafe code, but I wouldn't recommend that.
Upvotes: 5