mio
A fast, low-level, non-blocking I/O library for Rust that wraps epoll, kqueue, and IOCP behind one cross-platform event-polling API.
Repository Health
Technical Analysis
Mio (Metal I/O) is a low-level, non-blocking I/O library for Rust focused on event notification with as little overhead as possible over the underlying OS abstractions. It exposes a single small API — Poll, Registry, Events, Token, and Interest — that maps directly onto epoll on Linux, kqueue on BSD/macOS, and IOCP on Windows, so application code can register TCP, UDP, and Unix-domain socket sources once and drive them from one readiness-based event loop regardless of platform.
Mio deliberately stays narrow: it has zero required runtime dependencies, allocates nothing at runtime in its hot path, and explicitly omits file I/O, thread pools, and timers, leaving those to higher-level consumers. The most notable of those consumers is Tokio, which uses Mio as its OS-facing reactor — making Mio the foundational I/O layer underneath a large share of the async Rust ecosystem.
What You Get
- A
Poll/Registry/Events/Token/InterestAPI surface (five names) for registering I/O sources and waiting on readiness events - Non-blocking TCP, UDP, and Unix-domain socket primitives in
mio::net, gated behind thenetfeature flag - A cross-platform
Wakerfor interrupting a blockedpoll()call from another thread - Platform-specific extensions (
mio::unix,mio::windows) for things like Unix pipes and named pipes, gated behindos-ext - Feature-flagged compilation (
os-poll,os-ext,net) so consumers only pay for the surface area they actually use
Common Use Cases
- Building the reactor/event-loop layer underneath a higher-level async runtime (as Tokio does)
- Writing a high-throughput TCP or UDP server that needs direct control over readiness polling instead of an async runtime’s scheduling overhead
- Implementing custom protocol servers where predictable, low-allocation I/O behavior matters more than ergonomics
- Bridging a raw file descriptor or Windows handle into an event loop via
SourceFd/NamedPipe
Under The Hood
Architecture
Mio’s core types are Poll (src/poll.rs, ~814 lines), which owns a Registry and drives OS event notification, and Events/Token/Interest, which describe what happened and to which registered source. The sys module (src/sys/mod.rs) is the architectural seam: it cfg-selects between sys/unix (epoll/kqueue via a selector submodule), sys/windows (an IOCP-based selector built on the Windows AFD API in afd.rs/iocp.rs/overlapped.rs), sys/wasip1, and a sys/shell fallback that panics unless os-poll is enabled. Application code, net/tcp, net/uds, and waker.rs all funnel through this one re-export boundary, so the platform selector is the single point that has to stay correct for every downstream feature to work; nothing above sys contains OS-specific logic itself.
Tech Stack
Rust 2021 edition, MSRV pinned at 1.71 in Cargo.toml, with an explicit per-minor-version MSRV table maintained in the README. The only default dependency is optional log 0.4.8; Unix/Hermit/WASI targets add libc 0.2.183, Windows adds windows-sys 0.61 (scoped to the specific Wdk_*/Win32_* feature sets needed for AFD/IOCP), and WASI adds wasi 0.11.0. There is no async runtime, ORM, or web framework dependency anywhere — Mio sits underneath that layer rather than consuming it. Dev-dependencies (env_logger, rand) support tests and the three bundled examples/ binaries. CI (.github/workflows/ci.yml) builds and tests across the full matrix of supported OS/target combinations.
Code Quality
The crate root denies missing_docs, missing_debug_implementations, rust_2018_idioms, unused_imports, and dead_code, and denies warnings under test and doctest builds — a stricter lint posture than most libraries at this level of the stack. Tests live in a dedicated tests/ directory covering polling, TCP/UDP/UDS sockets, the waker, Windows named pipes, and regression cases, backed by a shared tests/util helper module and exercised across platforms in CI. Error handling is consistently std::io::Result-based with errno/OS-error translation isolated inside sys/*, rather than panics (the one intentional exception being the shell implementation’s panic when os-poll is disabled). There is no CONTRIBUTING.md, but contribution and MSRV policy are documented directly in the README.
API Design
The public surface is deliberately tiny — five names (Poll, Registry, Events, Token, Interest) cover the entire core workflow of register-then-poll-then-dispatch-on-token, and the README’s quickstart example is the same shape as real usage: no builder chains, no config objects. Doc examples are compiled as doctests (#![doc(test(attr(deny(warnings))))]), so the documentation can’t silently rot out of sync with the API. The unavoidable complexity is conceptual rather than accidental: readiness-based (as opposed to completion-based) I/O semantics take some getting used to, and Mio’s own README candidly points newcomers toward Tokio if they want something friendlier to start with.