use libc::{c_uchar, c_void, size_t};
use std::f64;
use std::ptr;
use std::slice;
use crate::ckmeans;
#[repr(C)]
pub struct WrapperArray {
pub data: *const c_void,
pub len: size_t,
}
#[repr(C)]
pub struct InternalArray {
pub data: *const c_void,
pub len: size_t,
}
#[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.cast(), arr.len) }
}
}
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.cast(),
len: blen as size_t,
}
}
}
impl From<Vec<f64>> for ExternalArray {
fn from(v: Vec<f64>) -> Self {
let boxed = v.into_boxed_slice();
let blen = boxed.len();
let rawp = Box::into_raw(boxed);
ExternalArray {
data: rawp.cast(),
len: blen as size_t,
}
}
}
impl From<Vec<Vec<f64>>> for WrapperArray {
fn from(arr: Vec<Vec<f64>>) -> Self {
let iarrs: Vec<InternalArray> = arr.into_iter().map(std::convert::Into::into).collect();
let boxed = iarrs.into_boxed_slice();
let blen = boxed.len();
let rawp = Box::into_raw(boxed);
WrapperArray {
data: rawp.cast(),
len: blen as size_t,
}
}
}
impl From<InternalArray> for Vec<f64> {
fn from(arr: InternalArray) -> Self {
unsafe {
let p = ptr::slice_from_raw_parts_mut(arr.data as _, arr.len);
Box::from_raw(p).into_vec()
}
}
}
impl From<WrapperArray> for Vec<Vec<f64>> {
fn from(arr: WrapperArray) -> Self {
let arrays = unsafe {
let p: *mut [InternalArray] = ptr::slice_from_raw_parts_mut(arr.data as _, arr.len);
Box::from_raw(p).into_vec()
};
arrays.into_iter().map(std::convert::Into::into).collect()
}
}
#[unsafe(no_mangle)]
pub extern "C" fn ckmeans_ffi(data: ExternalArray, classes: c_uchar) -> WrapperArray {
ckmeans(data.into(), classes).unwrap().into()
}
#[unsafe(no_mangle)]
pub extern "C" fn drop_ckmeans_result(result: WrapperArray) {
let _: Vec<Vec<f64>> = result.into();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ffi() {
let i = vec![
1f64, 12., 13., 14., 15., 16., 2., 2., 3., 5., 7., 1., 2., 5., 7., 1., 5., 82., 1.,
1.3, 1.1, 78.,
];
let res: Vec<Vec<f64>> = ckmeans_ffi(i.into(), 3).into();
let expected = vec![
vec![
1.0, 1.0, 1.0, 1.0, 1.1, 1.3, 2.0, 2.0, 2.0, 3.0, 5.0, 5.0, 5.0, 7.0, 7.0,
],
vec![12., 13., 14., 15., 16.],
vec![78., 82.],
];
assert_eq!(res, expected);
}
}