Step 2-Implementing a proper Executor 197 fn insert_task(&self, id: usize, task: Task) { CURRENT_EXEC. with(|q| q. tasks. borrow_mut(). insert(id, task)); } fn task_count(&self)-> usize { CURRENT_EXEC. with(|q| q. tasks. borrow(). len()) } So, we have six methods here: new -Creates a new Executor instance. For simplicity, we have no initialization here, and everything is done lazily by design in the thread_local! macro. pop_ready -This function takes a lock on read_queue and pops off an ID that's ready from the back of Vec. Calling pop here means that we also remove the item from the collection. As a side note, since Waker pushes its ID to the back of ready_queue and we pop off from the back as well, we essentially get a Last In First Out (LIFO ) queue. Using something such as Vec Deque from the standard library would easily allow us to choose the order in which we remove items from the queue if we wish to change that behavior. get_future -This function takes the ID of a top-level future as an argument, removes the future from the tasks collection, and returns it (if the task is found). This means that if the task returns Not Ready (signaling that we're not done with it), we need to remember to add it back to the collection again. get_waker -This function creates a new Waker instance. insert_task -This function takes an id property and a Task property and inserts them into our tasks collection. task_count -This function simply returns a count of how many tasks we have in the queue. The final and last part of the Executor implementation is the block_on function. This is also where we close the impl Executor block: ch08/b-reactor-executor/src/runtime/executor. rs pub fn block_on<F>(&mut self, future: F) where F: Future<Output = String> + 'static, { spawn(future); loop { while let Some(id) = self. pop_ready() {