1use std::ffi::{CStr, CString};
7use std::os::raw::{c_char, c_float, c_int};
8use std::ptr;
9use std::slice;
10use ghostflow_core::Tensor;
11
12#[repr(C)]
14pub struct GhostFlowTensor {
15 _private: [u8; 0],
16}
17
18#[repr(C)]
20pub struct GhostFlowModel {
21 _private: [u8; 0],
22}
23
24#[repr(C)]
26#[derive(Debug, Clone, Copy, PartialEq)]
27pub enum GhostFlowError {
28 Success = 0,
29 InvalidShape = 1,
30 InvalidData = 2,
31 NullPointer = 3,
32 AllocationFailed = 4,
33 ComputationFailed = 5,
34 Unknown = 99,
35}
36
37fn tensor_to_ptr(tensor: Tensor) -> *mut GhostFlowTensor {
39 Box::into_raw(Box::new(tensor)) as *mut GhostFlowTensor
40}
41
42unsafe fn ptr_to_tensor<'a>(ptr: *const GhostFlowTensor) -> Option<&'a Tensor> {
44 if ptr.is_null() {
45 None
46 } else {
47 Some(&*(ptr as *const Tensor))
48 }
49}
50
51unsafe fn ptr_to_tensor_mut<'a>(ptr: *mut GhostFlowTensor) -> Option<&'a mut Tensor> {
53 if ptr.is_null() {
54 None
55 } else {
56 Some(&mut *(ptr as *mut Tensor))
57 }
58}
59
60#[no_mangle]
62pub extern "C" fn ghostflow_init() -> GhostFlowError {
63 GhostFlowError::Success
64}
65
66#[no_mangle]
68pub extern "C" fn ghostflow_version() -> *const c_char {
69 let version = CString::new(env!("CARGO_PKG_VERSION")).unwrap();
70 version.into_raw()
71}
72
73#[no_mangle]
75pub unsafe extern "C" fn ghostflow_free_string(s: *mut c_char) {
76 if !s.is_null() {
77 let _ = CString::from_raw(s);
78 }
79}
80
81#[no_mangle]
93pub unsafe extern "C" fn ghostflow_tensor_create(
94 data: *const c_float,
95 data_len: usize,
96 shape: *const usize,
97 shape_len: usize,
98 out: *mut *mut GhostFlowTensor,
99) -> GhostFlowError {
100 if data.is_null() || shape.is_null() || out.is_null() {
101 return GhostFlowError::NullPointer;
102 }
103
104 let data_slice = slice::from_raw_parts(data, data_len);
105 let shape_slice = slice::from_raw_parts(shape, shape_len);
106
107 match Tensor::from_slice(data_slice, shape_slice) {
108 Ok(tensor) => {
109 *out = tensor_to_ptr(tensor);
110 GhostFlowError::Success
111 }
112 Err(_) => GhostFlowError::InvalidShape,
113 }
114}
115
116#[no_mangle]
118pub unsafe extern "C" fn ghostflow_tensor_zeros(
119 shape: *const usize,
120 shape_len: usize,
121 out: *mut *mut GhostFlowTensor,
122) -> GhostFlowError {
123 if shape.is_null() || out.is_null() {
124 return GhostFlowError::NullPointer;
125 }
126
127 let shape_slice = slice::from_raw_parts(shape, shape_len);
128 let numel: usize = shape_slice.iter().product();
129 let data = vec![0.0f32; numel];
130
131 match Tensor::from_slice(&data, shape_slice) {
132 Ok(tensor) => {
133 *out = tensor_to_ptr(tensor);
134 GhostFlowError::Success
135 }
136 Err(_) => GhostFlowError::InvalidShape,
137 }
138}
139
140#[no_mangle]
142pub unsafe extern "C" fn ghostflow_tensor_ones(
143 shape: *const usize,
144 shape_len: usize,
145 out: *mut *mut GhostFlowTensor,
146) -> GhostFlowError {
147 if shape.is_null() || out.is_null() {
148 return GhostFlowError::NullPointer;
149 }
150
151 let shape_slice = slice::from_raw_parts(shape, shape_len);
152 let numel: usize = shape_slice.iter().product();
153 let data = vec![1.0f32; numel];
154
155 match Tensor::from_slice(&data, shape_slice) {
156 Ok(tensor) => {
157 *out = tensor_to_ptr(tensor);
158 GhostFlowError::Success
159 }
160 Err(_) => GhostFlowError::InvalidShape,
161 }
162}
163
164#[no_mangle]
166pub unsafe extern "C" fn ghostflow_tensor_free(tensor: *mut GhostFlowTensor) {
167 if !tensor.is_null() {
168 let _ = Box::from_raw(tensor as *mut Tensor);
169 }
170}
171
172#[no_mangle]
174pub unsafe extern "C" fn ghostflow_tensor_shape(
175 tensor: *const GhostFlowTensor,
176 out_shape: *mut usize,
177 out_ndim: *mut usize,
178) -> GhostFlowError {
179 if tensor.is_null() || out_shape.is_null() || out_ndim.is_null() {
180 return GhostFlowError::NullPointer;
181 }
182
183 if let Some(t) = ptr_to_tensor(tensor) {
184 let shape = t.dims();
185 *out_ndim = shape.len();
186 ptr::copy_nonoverlapping(shape.as_ptr(), out_shape, shape.len());
187 GhostFlowError::Success
188 } else {
189 GhostFlowError::NullPointer
190 }
191}
192
193#[no_mangle]
195pub unsafe extern "C" fn ghostflow_tensor_data(
196 tensor: *const GhostFlowTensor,
197 out_data: *mut c_float,
198 out_len: *mut usize,
199) -> GhostFlowError {
200 if tensor.is_null() || out_data.is_null() || out_len.is_null() {
201 return GhostFlowError::NullPointer;
202 }
203
204 if let Some(t) = ptr_to_tensor(tensor) {
205 let data = t.data_f32();
206 *out_len = data.len();
207 ptr::copy_nonoverlapping(data.as_ptr(), out_data, data.len());
208 GhostFlowError::Success
209 } else {
210 GhostFlowError::NullPointer
211 }
212}
213
214#[no_mangle]
216pub unsafe extern "C" fn ghostflow_tensor_add(
217 a: *const GhostFlowTensor,
218 b: *const GhostFlowTensor,
219 out: *mut *mut GhostFlowTensor,
220) -> GhostFlowError {
221 if a.is_null() || b.is_null() || out.is_null() {
222 return GhostFlowError::NullPointer;
223 }
224
225 let tensor_a = match ptr_to_tensor(a) {
226 Some(t) => t,
227 None => return GhostFlowError::NullPointer,
228 };
229
230 let tensor_b = match ptr_to_tensor(b) {
231 Some(t) => t,
232 None => return GhostFlowError::NullPointer,
233 };
234
235 match tensor_a.add(&tensor_b) {
236 Ok(result) => {
237 unsafe { *out = tensor_to_ptr(result); }
238 GhostFlowError::Success
239 }
240 Err(_) => GhostFlowError::ComputationFailed,
241 }
242}
243
244#[no_mangle]
246pub unsafe extern "C" fn ghostflow_tensor_mul(
247 a: *const GhostFlowTensor,
248 b: *const GhostFlowTensor,
249 out: *mut *mut GhostFlowTensor,
250) -> GhostFlowError {
251 if a.is_null() || b.is_null() || out.is_null() {
252 return GhostFlowError::NullPointer;
253 }
254
255 let tensor_a = match ptr_to_tensor(a) {
256 Some(t) => t,
257 None => return GhostFlowError::NullPointer,
258 };
259
260 let tensor_b = match ptr_to_tensor(b) {
261 Some(t) => t,
262 None => return GhostFlowError::NullPointer,
263 };
264
265 match tensor_a.mul(&tensor_b) {
266 Ok(result) => {
267 unsafe { *out = tensor_to_ptr(result); }
268 GhostFlowError::Success
269 }
270 Err(_) => GhostFlowError::ComputationFailed,
271 }
272}
273
274#[no_mangle]
276pub unsafe extern "C" fn ghostflow_tensor_matmul(
277 a: *const GhostFlowTensor,
278 b: *const GhostFlowTensor,
279 out: *mut *mut GhostFlowTensor,
280) -> GhostFlowError {
281 if a.is_null() || b.is_null() || out.is_null() {
282 return GhostFlowError::NullPointer;
283 }
284
285 let tensor_a = match ptr_to_tensor(a) {
286 Some(t) => t,
287 None => return GhostFlowError::NullPointer,
288 };
289
290 let tensor_b = match ptr_to_tensor(b) {
291 Some(t) => t,
292 None => return GhostFlowError::NullPointer,
293 };
294
295 match tensor_a.matmul(tensor_b) {
296 Ok(result) => {
297 *out = tensor_to_ptr(result);
298 GhostFlowError::Success
299 }
300 Err(_) => GhostFlowError::ComputationFailed,
301 }
302}
303
304#[no_mangle]
306pub unsafe extern "C" fn ghostflow_tensor_reshape(
307 tensor: *const GhostFlowTensor,
308 new_shape: *const usize,
309 new_shape_len: usize,
310 out: *mut *mut GhostFlowTensor,
311) -> GhostFlowError {
312 if tensor.is_null() || new_shape.is_null() || out.is_null() {
313 return GhostFlowError::NullPointer;
314 }
315
316 let t = match ptr_to_tensor(tensor) {
317 Some(t) => t,
318 None => return GhostFlowError::NullPointer,
319 };
320
321 let shape_slice = slice::from_raw_parts(new_shape, new_shape_len);
322
323 match t.reshape(shape_slice) {
324 Ok(result) => {
325 *out = tensor_to_ptr(result);
326 GhostFlowError::Success
327 }
328 Err(_) => GhostFlowError::InvalidShape,
329 }
330}
331
332#[no_mangle]
334pub extern "C" fn ghostflow_get_last_error() -> *const c_char {
335 let msg = CString::new("No error").unwrap();
336 msg.into_raw()
337}
338
339#[cfg(test)]
340mod tests {
341 use super::*;
342
343 #[test]
344 fn test_tensor_create() {
345 unsafe {
346 let data = vec![1.0f32, 2.0, 3.0, 4.0];
347 let shape = vec![2, 2];
348 let mut tensor: *mut GhostFlowTensor = ptr::null_mut();
349
350 let result = ghostflow_tensor_create(
351 data.as_ptr(),
352 data.len(),
353 shape.as_ptr(),
354 shape.len(),
355 &mut tensor,
356 );
357
358 assert_eq!(result, GhostFlowError::Success);
359 assert!(!tensor.is_null());
360
361 ghostflow_tensor_free(tensor);
362 }
363 }
364
365 #[test]
366 fn test_tensor_zeros() {
367 unsafe {
368 let shape = vec![2, 3];
369 let mut tensor: *mut GhostFlowTensor = ptr::null_mut();
370
371 let result = ghostflow_tensor_zeros(
372 shape.as_ptr(),
373 shape.len(),
374 &mut tensor,
375 );
376
377 assert_eq!(result, GhostFlowError::Success);
378 assert!(!tensor.is_null());
379
380 ghostflow_tensor_free(tensor);
381 }
382 }
383}