Rust's async is in some places more difficult to use, because Rust is obsessed with avoiding allocations and dynamic dispatch.
Languages like C# and JS allocate a new object for every Promise and every listener. Rust bends backwards to avoid that, and make inlined strongly typed state machines instead. It creates limitations where you wouldn't expect, e.g. recursive calls need special handling, and abstract interfaces don't fully support async.
As for supporting both, it's just inconvenient to do, because many small syntactic and semantic differences mean it's hard to automate and cumbersome to maintain.
Not every await and new task produces an allocation in C#: ValueTask only allocates a state machine box if it yields asynchronously, plain task objects are pooled for common values and state machine box itself can also be pooled for frequently called methods (is opt-in), for example socket.SendAsync does not allocate thanks to this.
This will change further as "Runtime Handled Tasks" implementation comes along which will replace Roslyn-generated explicit state-machine code with runtime-provided suspension mechanism which will only yield/suspend the execution at true yield points, with further improvements to how the captured state that needs to persist across them is stored.
Languages like C# and JS allocate a new object for every Promise and every listener. Rust bends backwards to avoid that, and make inlined strongly typed state machines instead. It creates limitations where you wouldn't expect, e.g. recursive calls need special handling, and abstract interfaces don't fully support async.
As for supporting both, it's just inconvenient to do, because many small syntactic and semantic differences mean it's hard to automate and cumbersome to maintain.