I haven’t tried GATs. I’m using async_trait crate to poly fill needing that. I can’t recall offhand the unstable features I’m actually using. But generally I think async + traits don’t play well together currently (like you can get it to work but there’s a lot of surprising sharp edges and certain things that aren’t even possible yet). I’m also fully aware that I may not be writing “Rusty” code as I’m mainly coming from a C++ background and exploring Rust on my own.

Generally I’d say the async stuff is still pretty confusing. Like not if you’re entrenched in the Rust ecosystem but it seems like you have to choose the runtime you build around (Tokio vs async_std) and they’re drastically different maturity levels and feature sets so it’s more complex then just picking one as now you have to make sure the entire dependency train is consistent (or you end up with multiple competing implementations running within a system) which I’m concerned about as you scale up the complexity of a codebase (and writing code that doesn’t have to care is similarly difficult it seems where you kind of have to choose a specific dependency to get access to even basic I/O).

The other rough edge is that certain lifetime stuff in Rust still is over specified I’d consider. The example is unpacking a struct to be parameters for a function. Like

do_something(&mut self.x, &self.y)

complains that self ownership is being taken in conflicting ways and you have to add two dummy variables instead. It’s definitely better when I played with Rust a couple of years ago and it feels close but it still feels like those rough edges are an unnecessary barrier for beginners.

The other one is it feels like the compiler has reduced in power from suggesting what modification needs to be made. Either:

1) I’m writing more complex/different code than before. Possible since I’m doing an async codebase from scratch vs contributing to a more established Rust codebase.

2) most of the corrections it made before have already been incorporated in the automatic stuff the compiler is now inferring meaning the remaining pieces are the hard ones that have never had corrections in the first place.

3) the focus on auto-correction suggestion has diminished so new features are going in without considering as well as before how to guide the user to fix the issue (or these are harder suggestions in this space that haven’t been explored yet as the original suggestions were easier/better studied). The focus switch could even be intentional (other areas of the language need more focus)
4. I’m sure there’s other possibilities.

The final nit I’d note is one around crate discoverability. There’s a lot of crates out there and there’s a lack of documentation on them (ie are they abandoned, “finished”, active development) and selection criteria (ie which crate should I use given my project dependency chain, perhaps crowdsourced ML suggestions from other projects like a “Netflix” recommendation with ability to inject additional details like “I’m looking for something that provides certain algorithmic or memory guarantees, is async or not, etc” if those things aren’t available from the existing dependency but a new thing being added). The data is there nominally as fancy charts because that’s kind of easy but the harder proactive advice with explanations is the real gold no one has done and can really push Rust to the next level for engineering efficiency.