I'm working with a callback-based C api. I'm using this cool pattern I found on the internet to pass a boxed closure into C (I've tweaked the code to make the example simpler):
unsafe extern "C" fn generic_callback<F>(data: *mut c_void, userdata: *mut c_void)
where
F: FnMut(*mut c_void) + 'static,
{
let closure = &mut *(userdata as *mut F);
closure(data);
}
fn add_callback<F>(&mut self, closure: F)
where
F: FnMut(*mut c_void) + 'static,
{
let p = Box::into_raw(Box::new(closure));
let cb = generic_callback::<F>;
unsafe {
c_register_cb(cb, std::ptr::addr_of_mut!(*p) as *mut c_void);
}
}
Later on, I'd like to free the closure. Once I get the pointer back from C (let's ignore how that works because it's not important), I know I'm supposed to use Box::from_raw():
let _closure = Box::from_raw(p as *mut dyn FnMut(*mut c_void) as &mut _);
// _closure goes out of scope and is dropped
But this doesn't compile, because the T in Box<T> isn't known. Is there a way to generically drop a box pointer without instantiating it fully?
Box<dyn Foo> and &dyn Foo and *mut dyn Foo, etc, are wide pointers which consist of a pointer to the type-erased struct and a pointer to a static vtable. The vtable in turn contains the size of the type-erased struct, a pointer to the destructor, and other data. That's the "extra data" in the case of Box<dyn Foo>.
But you're not dealing with any of those, and even if you were, you would be throwing away the vtable pointer when you cast to a *mut c_void.
(There may be some additional confusion around what dyn Traitis. In particular, it's a concrete type but not a supertype or anything like that. A Box<F> where F: FnMut(*mut c_void) /* + Sized */ is not the same thing as a Box<dyn FnMut(*mut c_void)>. A Box<F> for any SizedF stores only a pointer to the data.)
An actually useful answer to your question will probably involve storing a type-erased wide pointer, but I'm still mulling the specifics over.