I'm rather inexperienced with rust and I am contemplating writing a C wrapper for a rust library.
Thus far I have found experiments for this very difficult, essentially because in order to write the wrapper I have to violate all of the safety mechanisms that rust is built around.
The main problem I have is around returning object pointers that can be wrapped on the other side. I think the main way to do this is supposed to be Box::leak
but in some cases this involves some pretty awkward extra copying even when my object comes from a Box
in the first place.
To make things a bit more concrete, I am trying to use arrow2
to expose a struct via a pointer. This package provides the struct ArrowArray
which is supposed to be binary compatible with the C struct defined here.
First, let me show the case that I understand:
#[no_mangle]
pub unsafe extern "C" fn array_pointer_demo() -> *mut c_void {
let a: Vec<i64> = vec![1, 2, 3, 4];
let abox = a.into_boxed_slice();
Box::leak(abox) as *mut _ as *mut _
}
Here I get back a pointer to the Vec
. I frankly am unsure about whether there is any copying going on here (I don't think so since Vec
should already be heap allocated), but at least I'm getting back a pointer to something that the stdlib docs assures me is not going to get freed. Indeed, this example and obvious variations of it seem to work fine.
I'm trying to use this in a very simple example in which I (think) I copy an array onto the heap (a.to_boxed()
) and then try to return its pointer.
#[no_mangle]
pub unsafe extern "C" fn arrow_direct() -> *const c_void {
let a = PrimitiveArray::<i64>::from_vec(vec![1, 2, 3]);
let a = &a as &dyn arrow2::array::Array;
//rust doesn't seem to be preserving this!
let abox = a.to_boxed();
&export_array_to_c(abox) as *const _ as *const _
}
This compiles, however it looks like the memory is getting freed. I think this makes sense to me, but I'm not sure what the alternative is.
What I'd like to do is somehow coerce the lifetime of the reference to 'static
but rust really does not like when I try to do this. For example
let _o = export_array_to_c(abox);
let o: &'static _ = &_o;
doesn't compile and the ructc --explain
strongly hints that coercion of lifetimes is not a thing. I don't understand why I can declare the output of Box::leak
static but I can't seem to create a 'static
reference on my own.
The only thing I can thing of which might work (though I haven't verified it to my satisfaction) is to instead create another box with Box::new(export_array_to_c(abox))
and then do Box::leak
on this, but this requires an extra copy.
Btw, I also do not understand why I need 2 as
clauses to convert to something compatible with a c_void
pointer. Box::leak
is already returning a reference to the underlying object and I don't understand why this can't be cast as a pointer or what the double as
means more generally.
Any advice appreciated, thanks!