Manually Implementing Future Trait
Here’s an example of implementing the Future trait for a custom data type in Rust. By manually implementing Future, you gain fine-grained control over how and when a task yields control and completes.
Custom Future Example
We will create a custom type, MyFuture, that resolves after a specified delay. It demonstrates implementing the Future trait by polling and returning a Poll state.
Code Example
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
time::{Duration, Instant},
};
use tokio::time::sleep;
/// A custom Future that resolves after a certain duration.
struct MyFuture {
start: Instant,
delay: Duration,
}
impl MyFuture {
fn new(delay: Duration) -> Self {
Self {
start: Instant::now(),
delay,
}
}
}
/// Implement the Future trait for MyFuture
impl Future for MyFuture {
type Output = String; // The type returned when the Future completes
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
// Check if enough time has passed since we started
if self.start.elapsed() >= self.delay {
// Return Poll::Ready when the delay has passed
Poll::Ready("Future complete!".to_string())
} else {
// Not ready yet, yield control back to the runtime
Poll::Pending
}
}
}
#[tokio::main]
async fn main() {
println!("Custom future starting...");
let my_future = MyFuture::new(Duration::from_secs(2));
// Await the custom future
let result = my_future.await;
println!("{}", result);
}
Explanation
- Custom Type:
MyFutureholds astarttime and adelayduration. It will resolve after the specified delay.
- Implementing
Future:- The
Futuretrait requires implementing thepollmethod. -
pollis called repeatedly by the executor until the future is ready (returnsPoll::Ready). - Inside
poll, we:- Check the elapsed time since the
start. - Return
Poll::Readywhen enough time has passed. - Return
Poll::Pendingotherwise, yielding control to the executor.
- Check the elapsed time since the
- The
- Using Pin:
- The
pollmethod takesself: Pin<&mut Self>to ensure the future is pinned in memory (a requirement for async programming).
- The
- Running the Future:
tokio::mainprovides the async runtime.- We create an instance of
MyFutureand await it.
Output
When you run the program, the output will look like this:
Custom future starting...
Future complete!
The program waits for 2 seconds before printing “Future complete!” because MyFuture resolves after the specified delay.
Key Takeaways
- Implementing the
Futuretrait allows full control over asynchronous behavior. - The
pollmethod is repeatedly called by the executor to check the state of the future. - You can use
Poll::Readywhen the future completes andPoll::Pendingto yield control back to the executor.