> how would a rust program handle a handle to the currently playing audio device being unplugged and invalidating your handle?
You would either represent this as all the operations having a Result which can be Unplugged or whatever, or you might decide (as the designer of that library) that you'll eat the error and silently ignore operations when unplugged, offering an unplugged() predicate so that callers can check whether they got unplugged if they care.
If you mean, what if the system is allowed to just invalidate handles we've got for some reason, without telling us about that, and then after invalidation they just mustn't be used, then you're screwed, regardless of programming language, that's a pretty bad design and there's nothing to be done about it.
A more common design (e.g. for OS file handles) has an explicit call where you give back the handle (close in the case of file handles), promising you won't use it again. If the handle is meanwhile broken for some reason anyway (e.g. user pulled out the USB stick with the file on it) then the OS will tell you about the problem, but you still need to acknowledge that by closing the broken handle, you don't just suddenly find there's a different file behind your existing handle now. It's no trouble to represent this properly in Rust.
Let's explain a bit more about why Rust cares about thread safety. Rust types can have marker traits named Send and Sync. Send means "You can safely give this type to another thread" and Sync means "You can safely give references to this type to another thread".
For example lets say I have a Goose, which is three 32-bit signed integers named x, y, z, plus three booleans flapping, honking and hissing. All six of those elements are Send, so Goose is Send. I can give a Goose to another thread no problem.
But the type Rc<Goose> isn't Send. Rc is a reference counted smart pointer, like shared_ptr<Goose> from C++ except it's not for threaded software. It's a little bit faster, especially on some CPUs, but you can't safely use it across threads. Rust has another reference counted smart point Arc, and Arc<Goose> is Send for the same reason shared_ptr<Goose> is thread safe in C++ -- it uses atomic integers for reference counting.
Because Rust tracks the marker traits for me, I don't need to carefully read documentation for a new type I'm using FunkyTractor to check whether it's thread safe. If it's Send then I can give it to another thread, and if it isn't then that program doesn't compile and I go "Aww" and use say a Mutex to wrap my FunkyTractor so that multiple threads can access it safely, then it will compile.
Only the people actually innovating tricky thread safety stuff (e.g. building your own spinlock) need to care about this, and make decisions like "Should this type I'm creating say it is Send?" for everybody else it's automatic.