Arc/Weak can only get you so far. The problem I have with Rust in the mentioned domains (gameplay programming, retained GUI, interpreters) is what makes it so good, sharing xor mutability. If you're writing lots of multi-threaded code it's fantastic. If your problem domain is like the ones mentioned it hurts you.
These are all highly non-parallel problems. They don't gain much from being parallel, and because Rust imposes 'restrict' semantics on even single threaded code you end up making it much harder to write code in these domains.
This has been my experience with Rust. Shared mutability is safe on a single thread without 'restrict' on all your pointers, and Rust has limited options to opt into shared mutability (with lots of ergonomic caveats).
Don't get me wrong though, I still think Rust is a great tool. It just has tradeoffs.
> Rust has limited options to opt into shared mutability
The idiomatic Rust equivalent of a C non-restrict pointer is arguably &Cell<T>. The biggest problem with it is library code that takes &mut T when the likes of &Cell<T> might suffice (because potential aliasing does not affect the semantics of what that Rust code is doing), but this is an acknowledged problem and the Rust project will take pull req's that fix it where it occurs.
Shared mutability can cause race conditions in single-threaded environments as well, if you need asynchronous contexts where mutations can be interleaved between suspension points. Think of events, message passing channels, I/O, timers, ticks...
If you're sure you're never going to need multi-threaded environment, you have an option as well: Replace std::sync with std::rc, Mutex with RefCell in the above toy example and that's about it.
If you want to use some asynchronous runtime, replace std::sync with tokio::sync (or std::rc), slap async/awaits along with a single-threaded runtime and that's about it.
Of course, the code above is just a toy example and business logic is much more complex in real world, but compare this to what it would take to write same C++ logic in async.
I found Rust's approach massively more ergonomic compared to C++ approach of passing closures around for asio-like IO contexts or coroutine compiler-magic which opens new novel avenues to shoot myself on the foot, well, to the extent I could grasp it.
It's true Rust forces you to pay all this cost ahead of time. It's also true most applications don't require this level of safety really, so it becomes ridiculous to pay it upfront. And even for some that require such high level of safety, you can skip bunch of bolts on a plane door and it will still be a billion dollar company at the end of the day, so...
These are all highly non-parallel problems. They don't gain much from being parallel, and because Rust imposes 'restrict' semantics on even single threaded code you end up making it much harder to write code in these domains.
This has been my experience with Rust. Shared mutability is safe on a single thread without 'restrict' on all your pointers, and Rust has limited options to opt into shared mutability (with lots of ergonomic caveats).
Don't get me wrong though, I still think Rust is a great tool. It just has tradeoffs.