An example of hand-written coroutines 139 This has some advantages, which I've covered before, but the most prominent ones are that they're very efficient and flexible. The downside is that you' d never want to write these state machines by hand (you'll see why in this chapter), so you need some kind of support from the compiler or another mechanism for rewriting your code to state machines instead of normal function calls. The result is that you get something that looks very simple. It looks like a function/subroutine that you can easily map to something that you can run using a simple call instruction in assembly, but what you actually get is something pretty complex and different from this, and it doesn't look anything like what you' d expect. Generators vs coroutines Generators are state machines as well, exactly the kind we'll cover in this chapter. They're usually implemented in a language to create state machines that yield values to the calling function. Theoretically, you could make a distinction between coroutines and generators based on what they yield to. Generators are usually limited to yielding to the calling function. Coroutines can yield to another coroutine, a scheduler, or simply the caller, in which case they're just like generators. In my eyes, there is really no point in making a distinction between them. They represent the same underlying mechanism for creating tasks that can pause and resume their executions, so in this book, we'll treat them as basically the same thing. Now that we've covered what coroutines are in text, we can start looking at what they look like in code. An example of hand-written coroutines The example we'll use going forward is a simplified version of Rust's asynchronous model. We'll create and implement the following: Our own simplified Future trait A simple HTTP client that can only make GET requests A task we can pause and resume implemented as a state machine Our own simplified async/await syntax called coroutine/wait A homemade preprocessor to transform our coroutine/wait functions into state machines the same way async/await is transformed So, to actually demystify coroutines, futures, and async/await, we will have to make some compromises. If we didn't, we' d end up re-implementing everything that is async/await and futures in Rust today, which is too much for just understanding the underlying techniques and concepts.