It would be the same sort of puzzle, if I had written the engine in C++17. The conclusion is that my starting point was just extremely bad to begin with and I should have just written a new hash table to begin with. Second time around I just wrote a hash table with buckets that stored a single u8 as data (next to the zobrist verification and depth), replaced the u8 with a properly constrained generic, and it was done.
With regarding to multi-threading and unsafe hash table access: I've indeed read that if you go above 2 threads (some people say 4) that performance tanks if you use Mutex locking. That would indeed be one the (very few) things I need to do unsafe, but I'll look into that when I get there. Before the engine reaches 3000 Elo, I won't even have to touch multi-cpu/multi-threading, because engines such as Minic and Texel can reach 3100+ on a single CPU.
Regrettably, it seems you dislike Rust for the wrong reasons. Because you _sometimes_ may need unsafe, it doesn't mean that the entire language is worthless and could just have been unsafe because of it. Sometimes you need a piece of dynamite to get stuff done, but it doesn't mean that you have to try and light candles with it, because, neh... a match or a lighter is too safe. Real men light candles with dynamite. Personally I'd prefer a language that can be used safe for 98% of the time, having to drop to unsafe if really needed or wanted, as compared to a language that is unsafe all the time.