How "safe" should a safe wrapper be?



While writing bindings to the Discord Game SDK, I started taking a very conservative approach to error handling and decided to catch any error I could.

Some errors have an almost impossible chance to crop up (pointers being null, UTF8 conversion failing, invalid enums) as the SDK itself is written in Rust, however only available through C bindings.

I’m beginning to wonder if I should continue on this path as it seems to become limiting now that I’m trying to implement iterators that end up making FFI calls (there is no way to express an error during iteration as far as I’m aware).

What are your thoughts on my issue?
What are examples of wrappers/bindings you find most idiomatic?
How much do you value safety in wrappers/bindings?

I couldn’t really find similar topics on this forum and through google searches, but if you know of similar discussions, I’d be happy to read up.

The repo is available, I apologize for the mess, it’s very much work in progress.



If an error is extremely unlikely to happen, you can .unwrap() or panic!().

Wrappers must be absolutely safe (as far as Rust’s definition of safety). If your wrapper could allow breaking any of Rust’s guarantees (allow mutable aliasing, dereference arbitrary pointers, cause data races, non-UTF8 str, etc.), you must mark your functions as unsafe.


This is possible by making the iterator yield Results, e.g. git2::References takes this approach. However this becomes very unergonomic to work with, so if the errors are ones that should never happen (i.e. the error happening means there is a bug in some of the local code, not related to the data being processed) then it can often make sense to just panic!.


I think this question is one of the reasons why the -sys split is a good idea; you can explore a variety of approaches to the wrappers. Some can be safer, some can be not.

This happened with graphics stuff a lot; you have a ton of different ways to wrap the opengl/vulkan apis. Some go for “as much compile time safety as possible”, some go for “this still will panic at runtime if you mess stuff up.”


Thank you very much for the responses so far.

I will have to read up more on Rust’s safety guarantees, I’ve been mostly learning through trial and error but it might be time to take a more methodical approach. I’m realising that although I’ve attempted to precautions and went ham with error handling, most of my code is not safe and ironically, some of the error handling I’ve written should definitely end up in panics instead.

I’m grateful I asked, haha