Naming specialized phantom type in Drop


#1

I’m writing a safe struct wrapper for a C struct that holds a “user_data” void* pointer. I’d like to use the void* pointer to hold an arbitrary Rust, with all type safety and proper cleanup with Drop.

To get a valid pointer I’m trying to use Box::new(rust_user_data) & Box::into_raw() as *mut c_void & Box::from_raw(void_ptr as *mut UserDataType).

I’m struggling with writing Drop implementation for my wrapper, because Drop doesn’t allow specialization. I can’t write impl<UserData> Drop for MyWrapper<Box<UserData>>.

But if I write impl<BoxedUserData> Drop for MyWrapper<BoxedUserData> I don’t have a way to name the type in the Box in order to cast *mut c_void to *mut UserData (the pointer type is very important here, as Box from *mut c_void causes leaks/crashes).

struct CType {context: *mut c_void} // In practice it's an opaque data type

struct RustWrapper<UserDataType> {
   handle: *mut CType,
   _marker: PhantomData<UserDataType>,
}

// error[E0366]:
impl<UserDataType> Drop for RustWrapper<Box<UserDataType>> {
   fn drop(&mut self) {
       Box::from_raw(self.get_c_void_context_pointer() as *mut UserDataType)
   }
}

Playpen: https://is.gd/yvIX8z

So how can I get to the actual data in Box<T> from Drop?

As an added complication, I’d like to support RustWrapper<UserDataType = ()> to make the user data optional. I can handle that by making the void* NULL.


#2

Can you use an enum instead, something akin to:

enum RustWrapper<T> {
    Boxed(*mut c_void, PhantomData<T>),
    Optional,
    Other(*mut c_void, PhantomData<T>)
}

impl<T> From<Box<T>> for RustWrapper<T> {
    fn from(b: Box<T>) -> Self {
        RustWrapper::Boxed(Box::into_raw(b) as *mut _, PhantomData)
    }
}

impl<T> Drop for RustWrapper<T> {
    fn drop(&mut self) {
        drop(unsafe {
            match *self {
                RustWrapper::Boxed(t, _) => {Box::from_raw(t as *mut T);},
                _ => {} // eliding handling of other cases
            }
        })
    }
}

#3

Your looking in wrong place. Remove the Box from structure impl and your code runs.

impl<UserDataType> RustWrapper<UserDataType> {

Using single letter for generic identifier would also make it less confusing.


#4

Ah, I’ve used RustWrapper<Box<UserDataType>>, so that I can have get_user_data() on it, and also implement RustWrapper<()> without the method.