use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_float, c_int};
use std::ptr;
use std::slice;
use ghostflow_core::Tensor;
#[repr(C)]
pub struct GhostFlowTensor {
_private: [u8; 0],
}
#[repr(C)]
pub struct GhostFlowModel {
_private: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GhostFlowError {
Success = 0,
InvalidShape = 1,
InvalidData = 2,
NullPointer = 3,
AllocationFailed = 4,
ComputationFailed = 5,
Unknown = 99,
}
fn tensor_to_ptr(tensor: Tensor) -> *mut GhostFlowTensor {
Box::into_raw(Box::new(tensor)) as *mut GhostFlowTensor
}
unsafe fn ptr_to_tensor<'a>(ptr: *const GhostFlowTensor) -> Option<&'a Tensor> {
if ptr.is_null() {
None
} else {
Some(&*(ptr as *const Tensor))
}
}
unsafe fn ptr_to_tensor_mut<'a>(ptr: *mut GhostFlowTensor) -> Option<&'a mut Tensor> {
if ptr.is_null() {
None
} else {
Some(&mut *(ptr as *mut Tensor))
}
}
#[no_mangle]
pub extern "C" fn ghostflow_init() -> GhostFlowError {
GhostFlowError::Success
}
#[no_mangle]
pub extern "C" fn ghostflow_version() -> *const c_char {
let version = CString::new(env!("CARGO_PKG_VERSION")).unwrap();
version.into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_free_string(s: *mut c_char) {
if !s.is_null() {
let _ = CString::from_raw(s);
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_create(
data: *const c_float,
data_len: usize,
shape: *const usize,
shape_len: usize,
out: *mut *mut GhostFlowTensor,
) -> GhostFlowError {
if data.is_null() || shape.is_null() || out.is_null() {
return GhostFlowError::NullPointer;
}
let data_slice = slice::from_raw_parts(data, data_len);
let shape_slice = slice::from_raw_parts(shape, shape_len);
match Tensor::from_slice(data_slice, shape_slice) {
Ok(tensor) => {
*out = tensor_to_ptr(tensor);
GhostFlowError::Success
}
Err(_) => GhostFlowError::InvalidShape,
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_zeros(
shape: *const usize,
shape_len: usize,
out: *mut *mut GhostFlowTensor,
) -> GhostFlowError {
if shape.is_null() || out.is_null() {
return GhostFlowError::NullPointer;
}
let shape_slice = slice::from_raw_parts(shape, shape_len);
let numel: usize = shape_slice.iter().product();
let data = vec![0.0f32; numel];
match Tensor::from_slice(&data, shape_slice) {
Ok(tensor) => {
*out = tensor_to_ptr(tensor);
GhostFlowError::Success
}
Err(_) => GhostFlowError::InvalidShape,
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_ones(
shape: *const usize,
shape_len: usize,
out: *mut *mut GhostFlowTensor,
) -> GhostFlowError {
if shape.is_null() || out.is_null() {
return GhostFlowError::NullPointer;
}
let shape_slice = slice::from_raw_parts(shape, shape_len);
let numel: usize = shape_slice.iter().product();
let data = vec![1.0f32; numel];
match Tensor::from_slice(&data, shape_slice) {
Ok(tensor) => {
*out = tensor_to_ptr(tensor);
GhostFlowError::Success
}
Err(_) => GhostFlowError::InvalidShape,
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_free(tensor: *mut GhostFlowTensor) {
if !tensor.is_null() {
let _ = Box::from_raw(tensor as *mut Tensor);
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_shape(
tensor: *const GhostFlowTensor,
out_shape: *mut usize,
out_ndim: *mut usize,
) -> GhostFlowError {
if tensor.is_null() || out_shape.is_null() || out_ndim.is_null() {
return GhostFlowError::NullPointer;
}
if let Some(t) = ptr_to_tensor(tensor) {
let shape = t.dims();
*out_ndim = shape.len();
ptr::copy_nonoverlapping(shape.as_ptr(), out_shape, shape.len());
GhostFlowError::Success
} else {
GhostFlowError::NullPointer
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_data(
tensor: *const GhostFlowTensor,
out_data: *mut c_float,
out_len: *mut usize,
) -> GhostFlowError {
if tensor.is_null() || out_data.is_null() || out_len.is_null() {
return GhostFlowError::NullPointer;
}
if let Some(t) = ptr_to_tensor(tensor) {
let data = t.data_f32();
*out_len = data.len();
ptr::copy_nonoverlapping(data.as_ptr(), out_data, data.len());
GhostFlowError::Success
} else {
GhostFlowError::NullPointer
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_add(
a: *const GhostFlowTensor,
b: *const GhostFlowTensor,
out: *mut *mut GhostFlowTensor,
) -> GhostFlowError {
if a.is_null() || b.is_null() || out.is_null() {
return GhostFlowError::NullPointer;
}
let tensor_a = match ptr_to_tensor(a) {
Some(t) => t,
None => return GhostFlowError::NullPointer,
};
let tensor_b = match ptr_to_tensor(b) {
Some(t) => t,
None => return GhostFlowError::NullPointer,
};
match tensor_a.add(&tensor_b) {
Ok(result) => {
unsafe { *out = tensor_to_ptr(result); }
GhostFlowError::Success
}
Err(_) => GhostFlowError::ComputationFailed,
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_mul(
a: *const GhostFlowTensor,
b: *const GhostFlowTensor,
out: *mut *mut GhostFlowTensor,
) -> GhostFlowError {
if a.is_null() || b.is_null() || out.is_null() {
return GhostFlowError::NullPointer;
}
let tensor_a = match ptr_to_tensor(a) {
Some(t) => t,
None => return GhostFlowError::NullPointer,
};
let tensor_b = match ptr_to_tensor(b) {
Some(t) => t,
None => return GhostFlowError::NullPointer,
};
match tensor_a.mul(&tensor_b) {
Ok(result) => {
unsafe { *out = tensor_to_ptr(result); }
GhostFlowError::Success
}
Err(_) => GhostFlowError::ComputationFailed,
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_matmul(
a: *const GhostFlowTensor,
b: *const GhostFlowTensor,
out: *mut *mut GhostFlowTensor,
) -> GhostFlowError {
if a.is_null() || b.is_null() || out.is_null() {
return GhostFlowError::NullPointer;
}
let tensor_a = match ptr_to_tensor(a) {
Some(t) => t,
None => return GhostFlowError::NullPointer,
};
let tensor_b = match ptr_to_tensor(b) {
Some(t) => t,
None => return GhostFlowError::NullPointer,
};
match tensor_a.matmul(tensor_b) {
Ok(result) => {
*out = tensor_to_ptr(result);
GhostFlowError::Success
}
Err(_) => GhostFlowError::ComputationFailed,
}
}
#[no_mangle]
pub unsafe extern "C" fn ghostflow_tensor_reshape(
tensor: *const GhostFlowTensor,
new_shape: *const usize,
new_shape_len: usize,
out: *mut *mut GhostFlowTensor,
) -> GhostFlowError {
if tensor.is_null() || new_shape.is_null() || out.is_null() {
return GhostFlowError::NullPointer;
}
let t = match ptr_to_tensor(tensor) {
Some(t) => t,
None => return GhostFlowError::NullPointer,
};
let shape_slice = slice::from_raw_parts(new_shape, new_shape_len);
match t.reshape(shape_slice) {
Ok(result) => {
*out = tensor_to_ptr(result);
GhostFlowError::Success
}
Err(_) => GhostFlowError::InvalidShape,
}
}
#[no_mangle]
pub extern "C" fn ghostflow_get_last_error() -> *const c_char {
let msg = CString::new("No error").unwrap();
msg.into_raw()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tensor_create() {
unsafe {
let data = vec![1.0f32, 2.0, 3.0, 4.0];
let shape = vec![2, 2];
let mut tensor: *mut GhostFlowTensor = ptr::null_mut();
let result = ghostflow_tensor_create(
data.as_ptr(),
data.len(),
shape.as_ptr(),
shape.len(),
&mut tensor,
);
assert_eq!(result, GhostFlowError::Success);
assert!(!tensor.is_null());
ghostflow_tensor_free(tensor);
}
}
#[test]
fn test_tensor_zeros() {
unsafe {
let shape = vec![2, 3];
let mut tensor: *mut GhostFlowTensor = ptr::null_mut();
let result = ghostflow_tensor_zeros(
shape.as_ptr(),
shape.len(),
&mut tensor,
);
assert_eq!(result, GhostFlowError::Success);
assert!(!tensor.is_null());
ghostflow_tensor_free(tensor);
}
}
}