Pointer constness for FFI

Suppose I have an opaque C type MyType and a C function get_name(MyType* p), and I'm going to invoke the function from Rust. Logically the function doesn't change the internal state of p, but the implementation may require a mutable pointer.
In this case, what should be signature of the corresponding function in Rust? More specifically, should I use p: *const MyType or p: *mut MyType?

it doesn't really matter as far as rust concerns: raw pointers can be casted between const and mut freely, the difference is mostly for human to reason about the source code.

but ffi function declarations usually follow their C signatures by convention, especially when you generate the bindings automatically. so I would stick to p: *mut MyType in this example.

1 Like

Well, why isn't it get_name(const MyType* p) in C?

1 Like

I agree with the previous replies. Even though the current implementation might not change the underlying object, this guarantee is not given by means of the function's signature.
This may indicate that the current behavior is an implementation detail, that the API does not want to expose. Thus, you should treat the pointer in Rust as *mut MyType.

It's a vendor library...

A further question: In the example above, for a safe Rust binding, should I follow the logical guarantee, i.e. use get_name(&MyType) instead of get_name(&mut MyType) and cast the pointer in an unsafe block?

If the vendor function takes a non-const pointer, it seems like you should require &mut MyType in the safe wrapper

You should probably not use &mut Foo on the Rust side, because that's a statement of exclusive access, which you probably can't guarantee given than you don't know what happens on the vendor's side of the library.

1 Like

*const IMHO.

It often happens that C libraries don't declare const even when they could, sometimes intentionally if the author considers C const correctness annoying or pointless.

I'd declare const/mut in FFI according to the library's documentation or de-facto behavior (if it can be relied on and the docs are lacking).

Note that Rust references are FFI-safe and compatible with C pointers. You could even use p: &MyType in function arguments if you're sure that the call won't modify MyType (or in advanced cases, that the modified parts are wrapped in an UnsafeCell from Rust's perspective).