Rust slices expose both a pointer to the first element (if any), and a len
getter.
These two elements are supposed to be used together for FFI, by letting you manipulate "C slices" (thinggy *
pointer + size_t count
).
You can create a convenience struct to hold both fields, as would be done in C, but one thing to be careful with is ownership: since a Vec
is allocated by Rust, you will need to give the owned slice back to Rust so that it can properly free it:
use ::core::{ptr, slice};
#[repr(C)]
pub
struct FFIBoxedSlice {
ptr: *mut SerialPortInfoFFI,
len: usize, // number of elems
}
// Helper (internal) function
fn vec_to_ffi (v: Vec<SerialPortInfoFFI>)
-> FFIBoxedSlice
{
// Going from Vec<_> to Box<[_]> just drops the (extra) `capacity`
let boxed_slice: Box<[SerialPortInfoFFI]> = v.into_boxed_slice();
let len = boxed_slice.len();
let fat_ptr: *mut [SerialPortInfoFFI] =
Box::into_raw(boxed_slice)
;
let slim_ptr: *mut SerialPortInfoFFI = fat_ptr as _;
FFIBoxedSlice { ptr: slim_ptr, len }
}
#[no_mangle]
pub
unsafe
extern "C"
fn free_boxed_slice (FFIBoxedSlice { ptr, len }: FFIBoxedSlice)
{
if ptr.is_null() {
eprintln!("free_boxed_slice() errored: got NULL ptr!");
::std::process::abort();
}
let slice: &mut [SerialPortInfoFFI] =
slice::from_raw_parts_mut(ptr, len)
;
drop(Box::from_raw(slice));
}