True. Rust's mandate for "zero runtime cost abstractions" is one of the better justifications for async/await. Because async/await, too, has significant limitations, notably:
1. Coloured functions
2. Placing the concurrency design decision (async vs not) on the implementer of a function, not the caller
3. Debugging complexity
(1) and (2) are mutually, negatively, reinforcing. As the implementer of a library function, I can't possibly know all the possible scenarios in which my function will be called. If I make it synchronous, then I'm blocking my caller. Which might be an issue - or might not. If I make it async then I don't block the caller - but I've just consigned the entire call stack to be async.
There's clearly strong opinions on both sides. Some are strong advocates of async/await. Personally, I'm not. Multiple, concurrent, fine-grained sequences of actions fit my mental model much better. Async/await doesn't give me that: I find reading async/await code to be a bit like reading control flow with GOTOs.
My preferences are undoubtedly influenced by working with Erlang, which has supported fine-grained sequences since the beginning. There are no coloured functions; just functions. As the caller, I can decide if I want things to run sequentialy (call from another function) or concurrently (spawn as a separate Erlang process). I have the context I need to make that decision.
It's not a panacea by any means (see e.g. Structured Concurrency [0]). But it fits my mental model much better.
I'm not fan of async, but I don't like to deny reality by saying just use Structured Concurrency/Green threads/Magic Multithreading Powder. They all have their trade-offs.
And to be fair they are working to solve Colored functions.
However, async is still half-baked because no support for async traits and other corner cases.
Which was again caused by async being in RFC, development hell.