I'm creating an FFI module which will allow arrays of floats (sent across the FFI boundary as an ExternalArray
) to be used to calculate a result, which will then be sent back. The result is a Vec<Vec<f64>>
. I've written all the From
impls to make the conversions ergonomic, but I wanted to check whether I've accidentally done something that's accidentally UB.
- I don't take ownership of the incoming
ExternalArray
as this happens in ato_vec()
call elsewhere – the slice isn't modified by my code. - I don't understand why
InternalArray
has to beClone
, for instance.
#[repr(C)]
pub struct ExternalArray {
pub data: *const c_void,
pub len: size_t,
}
impl From<ExternalArray> for &[f64] {
fn from(arr: ExternalArray) -> Self {
unsafe { slice::from_raw_parts(arr.data as *mut f64, arr.len) }
}
}
#[repr(C)]
pub struct WrapperArray {
pub data: *const c_void,
pub len: size_t,
}
#[repr(C)]
#[derive(Clone)]
pub struct InternalArray {
pub data: *const c_void,
pub len: size_t,
}
// prepare individual WrapperArray members to be leaked across the FFI boundary
impl From<Vec<f64>> for InternalArray {
fn from(v: Vec<f64>) -> Self {
let boxed = v.into_boxed_slice();
let blen = boxed.len();
let rawp = Box::into_raw(boxed);
InternalArray {
data: rawp as *const c_void,
len: blen as size_t,
}
}
}
// create leakable data structure
impl From<Vec<Vec<f64>>> for WrapperArray {
fn from(arr: Vec<Vec<f64>>) -> Self {
let iarrs: Vec<InternalArray> = arr.into_iter().map(|member| member.into()).collect();
let boxed = iarrs.into_boxed_slice();
let blen = boxed.len();
let rawp = Box::into_raw(boxed);
WrapperArray {
data: rawp as *const c_void,
len: blen as size_t,
}
}
}
// Reconstitute individual WrapperArray members so they can be dropped
impl From<InternalArray> for Vec<f64> {
fn from(arr: InternalArray) -> Self {
// we originated this data, so pointer-to-slice -> box -> vec
unsafe {
let p = ptr::slice_from_raw_parts_mut(arr.data as *mut f64, arr.len);
Box::from_raw(p).to_vec()
}
}
}
// Reconstitute a WrapperArray that has been returned across the FFI boundary so it can be dropped
impl From<WrapperArray> for Vec<Vec<f64>> {
fn from(arr: WrapperArray) -> Self {
let arrays = unsafe {
let p = ptr::slice_from_raw_parts_mut(arr.data as *mut InternalArray, arr.len);
Box::from_raw(p).to_vec()
};
arrays.into_iter().map(|arr| arr.into()).collect()
}
}