I'm writing a FFI wrapper to a C library outside my control. (FFmpeg in this case, but I think the question is more general).
I have this situation:
struct OwnedStruct {
c_lib_ptr: *mut CLibStruct,
}
impl Drop for OwnedStruct {
fn drop(&mut self) { unsafe { c_lib_free(self.c_lib_ptr) }; }
}
impl<'a> OwnedStruct {
fn get_inner(&'a self) -> InnerStruct<'a> {
InnerStruct( unsafe { (*self.c_lib_ptr).inner }, PhantomData)
}
}
struct InnerStruct<'a>(*const CLibInner, PhantomData<&'a CLibInner>);
I'm using InnerStruct
mostly for accessors to the inner data. First, it striked me that this must be a common pattern, and went looking for a data-structure to augment a pointer with a lifetime. Found none (in std). It then hit me, that I should be able to simply define InnerStruct
as (&'a CLibInner)
, but it got me thinking, that I cannot guarantee that there are no mutations being done on the C-side of the interface for the Lifetime of InnerStruct
. The C-lib uses inner threads in some cases, so even for a highly short-lived '&CLibInner', I can't really guarantee concurrent non-mutation.
What's the right thing to do here? From what I understand, the "one writer or many readers"-rule does not apply to pointers, only to references? Is my original solution as good as can be? In that case, it still seems like a pattern that should be fairly common in bindings? Are there any "canonical" crates that provide the helper I were looking for? (I need this in more than one place).