Runtimes, Wakers, and the Reactor-Executor Pattern 190 ready_queue -This is a reference that can be shared between threads to a Vec<usize>, where usize represents the ID of a task that's in the ready queue. We share this object with the executor so that we can push the task ID associated with the Waker onto that queue when it's ready. The implementation of our Waker will be quite simple: ch08/b-reactor-executor/src/runtime/executor. rs impl Waker { pub fn wake(&self) { self. ready_queue . lock() . map(|mut q| q. push(self. id)) . unwrap(); self. thread. unpark(); } } When Waker::wake is called, we first take a lock on the Mutex that protects the ready queue we share with the executor. We then push the id value that identifies the task that this Waker is associated with onto the ready queue. After that's done, we call unpark on the executor thread and wake it up. It will now find the task associated with this Waker in the ready queue and call poll on it. It's worth mentioning that many designs take a shared reference (for example, an Arc<... >) to the future/ task itself, and push that onto the queue. By doing so, they skip a level of indirection that we get here by representing the task as a usize instead of passing in a reference to it. However, I personally think this way of doing it is easier to understand and reason about, and the end result will be the same. 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.