They did a really nice job of building thin layers up the stack from byte buffers (bytes), to async-friendly logging (tracing), basic IO (mio), async runtime (tokio), generic request/response services (tower), HTTP (hyper), and a web framework (axum).
Each of the layers are useful independent of the other layers above, and every one is has a thoughtfully designed, pragmatic interface.
I think this argument refers more to Rust not having built-in support for async from the language’s v1.0 rather than the design of the Tokio stack. That has definitely led to unfortunate incompatibilities between libraries built for the different runtimes. However, the Rust language team took a super methodical approach to async support and the way that more async-related traits are slowly being standardized (first Futures and hopefully Stream, AsyncRead / AsyncWrite at some point in the not too distant future) seems like a long-term-great way of building into the language the abstractions everyone can get behind while leaving room for experimentation. I’m sure others would have different takes but I’m a fan.
Personally I love being able to experiment on the bleeding edge but waiting for a stable implementation, even if it takes 3 years to reach discussion on the RFC's. There are crates if you need it today, which operate on best-practice, but for an official solution I accept that it may take time for it to achieve acceptable standard library inclusion.
It's not standard library, which makes some believe it is of lesser quality (not fit for stl?). Tokio works splendidly and I don't think it's a common belief that it's hacky. That being said, language-wide, async is a bit less focused upon (not in stl, trait fns cannot be async, etc) but otherwise the integration is very good.
They did a really nice job of building thin layers up the stack from byte buffers (bytes), to async-friendly logging (tracing), basic IO (mio), async runtime (tokio), generic request/response services (tower), HTTP (hyper), and a web framework (axum).
Each of the layers are useful independent of the other layers above, and every one is has a thoughtfully designed, pragmatic interface.