Design and introduction to epoll 67 As I mentioned at the start of this chapter, we'll take our inspiration from mio. This has one big upside and one downside. The upside is that we get a gentle introduction to how mio is designed, making it much easier to dive into that code base if you want to learn more than what we cover in this example. The downside is that we introduce an overly thick abstraction layer over epoll, including some design decisions that are very specific to mio. I think the upsides outweigh the downsides for the simple reason that if you ever want to implement a production-quality event loop, you'll probably want to look into the implementations that are already out there, and the same goes for if you want to dig deeper into the building blocks of asynchronous programming in Rust. In Rust, mio is one of the important libraries underpinning much of the async ecosystem, so gaining a little familiarity with it is an added bonus. It's important to note that mio is a cross-platform library that creates an abstraction over epoll, kqueue, and IOCP (through Wepoll, as we described in Chapter 3 ). Not only that, mio supports i OS and Android, and in the future, it will likely support other platforms as well. So, leaving the door open to unify an API over so many different systems is bound to also come with some compromises if you compare it to what you can achieve if you only plan to support one platform. mio mio describes itself as a “ fast, low-level I/O library for Rust focusing on non-blocking APIs and event notification for building performance I/O apps with as little overhead as possible over the OS abstractions. ” mio drives the event queue in Tokio, which is one of the most popular and widely used asynchronous runtimes in Rust. This means that mio is driving I/O for popular frameworks such as Actix Web ( https://actix. rs/ ), Warp (https://github. com/seanmonstar/ warp ), and Rocket ( https://rocket. rs/ ). The version of mio we'll use as design inspiration in this example is version 0. 8. 8. The API has changed in the past and may change in the future, but the parts of the API we cover here have been stable since 2019, so it's a good bet that there will not be significant changes to it in the near future. As is the case with all cross-platform abstractions, it's often necessary to go the route of choosing the least common denominator. Some choices will limit flexibility and efficiency on one or more platforms in the pursuit of having a unified API that works with all of them. We'll discuss some of those choices in this chapter. Before we go further, let's create a blank project and give it a name. We'll refer to it as a-epoll going forward, but you will of course need to replace that with the name you choose. Enter the folder and type the cargo init command.