For a library that deals with hardware and aims for compatibility, C seems like the obvious choice. Most languages have C bindings, and most hardware-oriented libraries have a C interface. Rust looks like a nice language and could be used for all the internal logic, but expose C interfaces to the outside world for compatibility (I think Rust can do that).
It's not really a technical reason as much as it is personal.
It's not C/C++ because I loathe C/C++, and if I never write C/C++ again, it will be too soon. The reasons for these feelings are borne out of decades of experience with them.
Of course, I'm currently an embedded engineer again at the moment, so "never" is actually "every day" unfortunately. Luckily embedded Rust is really looking good these days, and I've been using it a bit lately.
I don't really care about what other libraries do, and really, Buttplug isn't your normal "hardware driver" library. Either way, other libraries made their choices, I made mine. I hate C/C++ enough that I'd never spend my free time on it, and this is basically my back yard shed project that also happens to be a business, so it gets done with technologies I'm comfortable in.
As for exposing things, I mention that C/C++ FFI is coming in the post, mostly for Unreal Engine support. I currently have Rust exposing cdecl calls for the FFI, but it's bottlenecked to be as few calls as possible, mostly flinging protobufs back and forth because that's easy. The main thing holding up C/C++ FFI is figuring out how to translate some of the async paradigms I use to C/C++ in a way that will be generally useful.
For a library that deals with hardware and aims for compatibility, C seems like the obvious choice. Most languages have C bindings, and most hardware-oriented libraries have a C interface. Rust looks like a nice language and could be used for all the internal logic, but expose C interfaces to the outside world for compatibility (I think Rust can do that).