4 ms·
This is the essence of Rusts lifetime analysis; a pointer to an object can't be live for longer than the object itself is. In this particular example, you'd ma
by dwattttt 3y ago
This is the essence of Rusts lifetime analysis; a pointer to an object can't be live for longer than the object itself is.
In this particular example, you'd make an object with a finalizer and hide the raw pointer inside of it. Then you can only touch that pointer by going through a Rust object which participates in lifetime analysis, and it'll clean it up when it's done. Any more attempts to touch that object/pointer will fail to compile.
Expressed that way it makes sense that some people call it "GC at compile time".
- arcticbull 3y agoI like using this neat newtype for wrapping FFI objects. pub struct OwnedForeignInstance(NonNull<std::ffi::c_void>); You can then, as you say, implement Drop to give up the foreign object when it's no longer needed. impl Drop for OwnedForeignInstance { fn drop(&mut self) { unsafe { /* Destroy self.0.as_ptr() */ } } } You can define an un-owned reference to the owned foreign instance using a newtype like this. pub struct UnownedReference(PhantomData<UnsafeCell<*mut ()>>); Then, you can hand out zero-cost lifetime-checked references to the owned foreign instance like this. impl Deref for OwnedForeignInstance { type Target = UnownedReference; fn deref(&self) -> &Self::Target { unsafe { &*(self.0.as_ptr() as *mut _) } } } impl DerefMut for OwnedForeignInstance { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self.0.as_ptr() as *mut _) } } } Once you've done that, you expose your FFI functionality on UnownedReference, relying on auto-deref. Unless it consumes the receiver, in which case you put it on the OwnedForeignInstance. This way you can't destroy the object while references to it continue to exist. It's not perfect, but it's the best way I've found so far for making FFI wrapper objects that look and feel like Rust objects while respecting the FFI contract.