How does this Waker compare to the one in the standard library?
The Waker we create here will take the same role as the Waker type from the standard library. The biggest difference is that the std::task::Waker method is wrapped in a Context struct and requires us to jump through a few hoops when we create it ourselves. Don’t worry – we’ll do all this at the end of this book, but neither of these differences is important for understanding the role it plays, so that’s why we stick to our own simplified version of asynchronous Rust for now.
The last thing we need to do is to change the definition of the Future trait so that it takes &Waker as an argument.
Changing the Future definition
Since our Future definition is in the future.rs file, we start by opening that file.
The first thing we need to change is to pull in the Waker so that we can use it. At the top of the file, add the following code:
ch08/b-reactor-executor/src/future.rs
use crate::runtime::Waker;
The next thing we do is to change our Future trait so that it takes &Waker as an argument:
ch08/b-reactor-executor/src/future.rs
pub trait Future {
type Output;
fn poll(&mut self
, waker: &Waker
) -> PollState<Self::Output>;
}
At this point, you have a choice. We won’t be using the join_all function or the JoinAll<F: Future> struct going forward.
If you don’t want to keep them, you can just delete everything related to join_all, and that’s all you need to do in future.rs.
If you want to keep them for further experimentation, you need to change the Future implementation for JoinAll so that it accepts a waker: &Waker argument, and remember to pass the Waker when polling the joined futures in match fut.poll(waker).
The remaining things to do in step 1 are to make some minor changes where we implement the Future trait.
Let’s start in http.rs. The first thing we do is adjust our dependencies a little to reflect the changes we made to our runtime module, and we add a dependency on our new Waker. Replace the dependencies section at the top of the file with this:
ch08/b-reactor-executor/src/http.rs
use crate::{future::PollState, runtime::{self, reactor, Waker}, Future};
use mio::Interest;
use std::io::{ErrorKind, Read, Write};
The compiler will complain about not finding the reactor yet, but we’ll get to that shortly.
Next, we have to navigate to the impl Future for HttpGetFuture block, where we need to change the poll method so that it accepts a &Waker argument:
ch08/b-reactor-executor/src/http.rs
impl Future for HttpGetFuture {
type Output = String;
fn poll(&mut self
, waker: &Waker
) -> PollState<Self::Output> {
…
The last file we need to change is main.rs. Since corofy doesn’t know about Waker types, we need to change a few lines in the coroutines it generated for us in main.rs.
First of all, we have to add a dependency on our new Waker, so add this at the start of the file:
ch08/b-reactor-executor/src/main.rs
use runtime::Waker;
In the impl Future for Coroutineblock, change the following three lines of code that I’ve highlighted:
ch08/b-reactor-executor/src/main.rs
fn poll(&mut self
, waker: &Waker
)
match f1.poll(
waker
)
match f2.poll(
waker
)
And that’s all we need to do in step 1. We’ll get back to fixing the errors in this file as the last step we do; for now, we just focus on everything concerning the Waker.
The next step will be to create a proper Executor.