1#![allow(dead_code)]
7
8use crate::c_api::*;
9use std::ffi::CStr;
10use std::os::raw::{c_char, c_float, c_int, c_void};
11use std::ptr;
12
13#[no_mangle]
15pub unsafe extern "C" fn csharp_tensor_new(
16 data: *const c_void,
17 shape: *const c_int,
18 ndim: c_int,
19 dtype: c_int,
20) -> *mut TorshTensor {
21 let shape_vec: Vec<usize> = std::slice::from_raw_parts(shape, ndim as usize)
23 .iter()
24 .map(|&x| x as usize)
25 .collect();
26
27 let torsh_dtype = match dtype {
29 0 => TorshDType::F32,
30 1 => TorshDType::F64,
31 2 => TorshDType::I32,
32 3 => TorshDType::I64,
33 4 => TorshDType::U8,
34 _ => TorshDType::F32, };
36
37 torsh_tensor_new(data, shape_vec.as_ptr(), shape_vec.len(), torsh_dtype)
38}
39
40#[no_mangle]
42pub unsafe extern "C" fn csharp_tensor_from_float_array(
43 data: *const c_float,
44 _data_len: c_int,
45 shape: *const c_int,
46 ndim: c_int,
47) -> *mut TorshTensor {
48 let shape_vec: Vec<usize> = std::slice::from_raw_parts(shape, ndim as usize)
50 .iter()
51 .map(|&x| x as usize)
52 .collect();
53
54 torsh_tensor_new(
55 data as *const c_void,
56 shape_vec.as_ptr(),
57 shape_vec.len(),
58 TorshDType::F32,
59 )
60}
61
62#[no_mangle]
64pub unsafe extern "C" fn csharp_tensor_from_double_array(
65 data: *const c_float, _data_len: c_int,
67 shape: *const c_int,
68 ndim: c_int,
69) -> *mut TorshTensor {
70 let shape_vec: Vec<usize> = std::slice::from_raw_parts(shape, ndim as usize)
71 .iter()
72 .map(|&x| x as usize)
73 .collect();
74
75 torsh_tensor_new(
76 data as *const c_void,
77 shape_vec.as_ptr(),
78 shape_vec.len(),
79 TorshDType::F64,
80 )
81}
82
83#[no_mangle]
85pub unsafe extern "C" fn csharp_tensor_from_int_array(
86 data: *const c_int,
87 _data_len: c_int,
88 shape: *const c_int,
89 ndim: c_int,
90) -> *mut TorshTensor {
91 let shape_vec: Vec<usize> = std::slice::from_raw_parts(shape, ndim as usize)
92 .iter()
93 .map(|&x| x as usize)
94 .collect();
95
96 torsh_tensor_new(
97 data as *const c_void,
98 shape_vec.as_ptr(),
99 shape_vec.len(),
100 TorshDType::I32,
101 )
102}
103
104#[no_mangle]
106pub unsafe extern "C" fn csharp_tensor_add(
107 a: *mut TorshTensor,
108 b: *mut TorshTensor,
109) -> *mut TorshTensor {
110 let error = torsh_tensor_add(a, b, a);
112 if error != TorshError::Success {
113 return std::ptr::null_mut();
114 }
115 a
116}
117
118#[no_mangle]
120pub unsafe extern "C" fn csharp_tensor_subtract(
121 a: *mut TorshTensor,
122 b: *mut TorshTensor,
123) -> *mut TorshTensor {
124 let error = torsh_tensor_sub(a, b, a);
126 if error != TorshError::Success {
127 return std::ptr::null_mut();
128 }
129 a
130}
131
132#[no_mangle]
134pub unsafe extern "C" fn csharp_tensor_multiply(
135 a: *mut TorshTensor,
136 b: *mut TorshTensor,
137) -> *mut TorshTensor {
138 let error = torsh_tensor_mul(a, b, a);
140 if error != TorshError::Success {
141 return std::ptr::null_mut();
142 }
143 a
144}
145
146#[no_mangle]
148pub unsafe extern "C" fn csharp_tensor_matmul(
149 a: *mut TorshTensor,
150 b: *mut TorshTensor,
151) -> *mut TorshTensor {
152 let error = torsh_tensor_matmul(a, b, a);
154 if error != TorshError::Success {
155 return std::ptr::null_mut();
156 }
157 a
158}
159
160#[no_mangle]
162pub unsafe extern "C" fn csharp_tensor_relu(tensor: *mut TorshTensor) -> *mut TorshTensor {
163 let result = torsh_tensor_relu(tensor as *const TorshTensor, tensor);
165 match result {
166 crate::c_api::TorshError::Success => tensor,
167 _ => std::ptr::null_mut(),
168 }
169}
170
171#[no_mangle]
173pub unsafe extern "C" fn csharp_tensor_get_shape(
174 tensor: *mut TorshTensor,
175 shape: *mut c_int,
176 max_dims: c_int,
177 actual_dims: *mut c_int,
178) -> c_int {
179 let mut temp_shape = vec![0usize; max_dims as usize];
180 let mut ndim = 0usize;
181
182 let result = torsh_tensor_shape(tensor, temp_shape.as_mut_ptr(), &mut ndim);
183
184 if result == TorshError::Success {
185 *actual_dims = ndim as c_int;
186
187 for i in 0..std::cmp::min(ndim, max_dims as usize) {
189 *shape.add(i) = temp_shape[i] as c_int;
190 }
191
192 0 } else {
194 1 }
196}
197
198#[no_mangle]
200pub unsafe extern "C" fn csharp_tensor_get_float_data(
201 tensor: *mut TorshTensor,
202 data: *mut c_float,
203 max_elements: c_int,
204 actual_elements: *mut c_int,
205) -> c_int {
206 let result = torsh_tensor_data(tensor as *const TorshTensor);
209
210 if !result.is_null() {
211 let src_data = std::slice::from_raw_parts(result as *const c_float, max_elements as usize);
214 let dst_data = std::slice::from_raw_parts_mut(data, max_elements as usize);
215 dst_data.copy_from_slice(src_data);
216 *actual_elements = max_elements; 0 } else {
219 1 }
221}
222
223#[no_mangle]
225pub unsafe extern "C" fn csharp_tensor_dispose(tensor: *mut TorshTensor) {
226 torsh_tensor_free(tensor)
227}
228
229#[no_mangle]
231pub unsafe extern "C" fn csharp_linear_new(
232 in_features: c_int,
233 out_features: c_int,
234 bias: c_int, ) -> *mut TorshModule {
236 torsh_linear_new(in_features as usize, out_features as usize, bias != 0)
237}
238
239#[no_mangle]
241pub unsafe extern "C" fn csharp_linear_forward(
242 module: *mut TorshModule,
243 input: *mut TorshTensor,
244) -> *mut TorshTensor {
245 let result = torsh_linear_forward(
248 module as *const TorshModule,
249 input as *const TorshTensor,
250 input,
251 );
252 match result {
253 crate::c_api::TorshError::Success => input,
254 _ => std::ptr::null_mut(),
255 }
256}
257
258#[no_mangle]
260pub unsafe extern "C" fn csharp_module_dispose(module: *mut TorshModule) {
261 torsh_module_free(module)
262}
263
264#[no_mangle]
266pub unsafe extern "C" fn csharp_sgd_new(
267 learning_rate: c_float,
268 momentum: c_float,
269) -> *mut TorshOptimizer {
270 torsh_sgd_new(learning_rate, momentum)
271}
272
273#[no_mangle]
275pub unsafe extern "C" fn csharp_adam_new(
276 learning_rate: c_float,
277 beta1: c_float,
278 beta2: c_float,
279 epsilon: c_float,
280) -> *mut TorshOptimizer {
281 torsh_adam_new(learning_rate, beta1, beta2, epsilon)
282}
283
284#[no_mangle]
286pub unsafe extern "C" fn csharp_optimizer_step(
287 optimizer: *mut TorshOptimizer,
288 _parameters: *mut *mut TorshTensor,
289 _gradients: *mut *mut TorshTensor,
290 _param_count: c_int,
291) -> c_int {
292 let result = torsh_optimizer_step(optimizer);
294
295 match result {
296 TorshError::Success => 0,
297 _ => 1,
298 }
299}
300
301#[no_mangle]
303pub unsafe extern "C" fn csharp_optimizer_dispose(optimizer: *mut TorshOptimizer) {
304 torsh_optimizer_free(optimizer)
305}
306
307#[no_mangle]
309pub unsafe extern "C" fn csharp_get_last_error(buffer: *mut c_char, buffer_size: c_int) -> c_int {
310 let error_ptr = torsh_get_last_error();
311
312 if error_ptr.is_null() {
313 return 0; }
315
316 let error_cstr = CStr::from_ptr(error_ptr);
317 let error_bytes = error_cstr.to_bytes();
318
319 let copy_len = std::cmp::min(error_bytes.len(), (buffer_size - 1) as usize);
320
321 if copy_len > 0 {
322 ptr::copy_nonoverlapping(error_bytes.as_ptr(), buffer as *mut u8, copy_len);
323 *buffer.add(copy_len) = 0; }
325
326 error_bytes.len() as c_int
327}
328
329#[no_mangle]
331pub unsafe extern "C" fn csharp_clear_last_error() {
332 torsh_clear_last_error()
333}
334
335#[no_mangle]
337pub unsafe extern "C" fn csharp_get_version(buffer: *mut c_char, buffer_size: c_int) -> c_int {
338 let version_ptr = torsh_version();
339
340 if version_ptr.is_null() {
341 return 0;
342 }
343
344 let version_cstr = CStr::from_ptr(version_ptr);
345 let version_bytes = version_cstr.to_bytes();
346
347 let copy_len = std::cmp::min(version_bytes.len(), (buffer_size - 1) as usize);
348
349 if copy_len > 0 {
350 ptr::copy_nonoverlapping(version_bytes.as_ptr(), buffer as *mut u8, copy_len);
351 *buffer.add(copy_len) = 0; }
353
354 version_bytes.len() as c_int
355}
356
357#[no_mangle]
359pub unsafe extern "C" fn csharp_cuda_is_available() -> c_int {
360 torsh_cuda_is_available()
361}
362
363#[no_mangle]
365pub unsafe extern "C" fn csharp_cuda_device_count() -> c_int {
366 torsh_cuda_device_count()
367}
368
369#[no_mangle]
371pub unsafe extern "C" fn csharp_tensor_zeros(
372 shape: *const c_int,
373 ndim: c_int,
374 dtype: c_int,
375) -> *mut TorshTensor {
376 let shape_vec: Vec<usize> = std::slice::from_raw_parts(shape, ndim as usize)
377 .iter()
378 .map(|&x| x as usize)
379 .collect();
380
381 let total_elements: usize = shape_vec.iter().product();
382 let zeros_data = vec![0.0f32; total_elements];
383
384 let torsh_dtype = match dtype {
385 0 => TorshDType::F32,
386 1 => TorshDType::F64,
387 2 => TorshDType::I32,
388 3 => TorshDType::I64,
389 4 => TorshDType::U8,
390 _ => TorshDType::F32,
391 };
392
393 torsh_tensor_new(
394 zeros_data.as_ptr() as *const c_void,
395 shape_vec.as_ptr(),
396 shape_vec.len(),
397 torsh_dtype,
398 )
399}
400
401#[no_mangle]
403pub unsafe extern "C" fn csharp_tensor_ones(
404 shape: *const c_int,
405 ndim: c_int,
406 dtype: c_int,
407) -> *mut TorshTensor {
408 let shape_vec: Vec<usize> = std::slice::from_raw_parts(shape, ndim as usize)
409 .iter()
410 .map(|&x| x as usize)
411 .collect();
412
413 let total_elements: usize = shape_vec.iter().product();
414 let ones_data = vec![1.0f32; total_elements];
415
416 let torsh_dtype = match dtype {
417 0 => TorshDType::F32,
418 1 => TorshDType::F64,
419 2 => TorshDType::I32,
420 3 => TorshDType::I64,
421 4 => TorshDType::U8,
422 _ => TorshDType::F32,
423 };
424
425 torsh_tensor_new(
426 ones_data.as_ptr() as *const c_void,
427 shape_vec.as_ptr(),
428 shape_vec.len(),
429 torsh_dtype,
430 )
431}
432
433#[cfg(test)]
434mod tests {
435 use super::*;
436
437 #[test]
438 fn test_csharp_tensor_creation() {
439 let data = vec![1.0f32, 2.0, 3.0, 4.0];
440 let shape = vec![2i32, 2i32];
441
442 unsafe {
443 let tensor = csharp_tensor_from_float_array(
444 data.as_ptr(),
445 data.len() as c_int,
446 shape.as_ptr(),
447 shape.len() as c_int,
448 );
449
450 assert!(!tensor.is_null());
451
452 let mut retrieved_shape = vec![0i32; 2];
454 let mut actual_dims = 0i32;
455 let result =
456 csharp_tensor_get_shape(tensor, retrieved_shape.as_mut_ptr(), 2, &mut actual_dims);
457
458 assert_eq!(result, 0); assert_eq!(actual_dims, 2);
460 assert_eq!(retrieved_shape, shape);
461
462 csharp_tensor_dispose(tensor);
464 }
465 }
466
467 #[test]
468 fn test_csharp_tensor_operations() {
469 let data1 = vec![1.0f32, 2.0, 3.0, 4.0];
470 let data2 = vec![5.0f32, 6.0, 7.0, 8.0];
471 let shape = vec![2i32, 2i32];
472
473 unsafe {
474 let tensor1 = csharp_tensor_from_float_array(
475 data1.as_ptr(),
476 data1.len() as c_int,
477 shape.as_ptr(),
478 shape.len() as c_int,
479 );
480
481 let tensor2 = csharp_tensor_from_float_array(
482 data2.as_ptr(),
483 data2.len() as c_int,
484 shape.as_ptr(),
485 shape.len() as c_int,
486 );
487
488 assert!(!tensor1.is_null());
489 assert!(!tensor2.is_null());
490
491 let result = csharp_tensor_add(tensor1, tensor2);
493 assert!(!result.is_null());
494
495 csharp_tensor_dispose(tensor1);
497 csharp_tensor_dispose(tensor2);
498 csharp_tensor_dispose(result);
499 }
500 }
501
502 #[test]
503 fn test_csharp_zeros_ones() {
504 let shape = vec![3i32, 3i32];
505
506 unsafe {
507 let zeros = csharp_tensor_zeros(shape.as_ptr(), shape.len() as c_int, 0);
509 assert!(!zeros.is_null());
510
511 let ones = csharp_tensor_ones(shape.as_ptr(), shape.len() as c_int, 0);
513 assert!(!ones.is_null());
514
515 csharp_tensor_dispose(zeros);
517 csharp_tensor_dispose(ones);
518 }
519 }
520
521 #[test]
522 fn test_csharp_linear_layer() {
523 unsafe {
524 let linear = csharp_linear_new(4, 2, 1);
526 assert!(!linear.is_null());
527
528 let input_data = vec![1.0f32, 2.0, 3.0, 4.0];
530 let input_shape = vec![1i32, 4i32];
531
532 let input_tensor = csharp_tensor_from_float_array(
533 input_data.as_ptr(),
534 input_data.len() as c_int,
535 input_shape.as_ptr(),
536 input_shape.len() as c_int,
537 );
538
539 let output = csharp_linear_forward(linear, input_tensor);
540 assert!(!output.is_null());
541
542 csharp_tensor_dispose(input_tensor);
544 csharp_tensor_dispose(output);
545 csharp_module_dispose(linear);
546 }
547 }
548
549 #[test]
550 fn test_csharp_optimizers() {
551 unsafe {
552 let sgd = csharp_sgd_new(0.01, 0.9);
554 assert!(!sgd.is_null());
555
556 let adam = csharp_adam_new(0.001, 0.9, 0.999, 1e-8);
558 assert!(!adam.is_null());
559
560 csharp_optimizer_dispose(sgd);
562 csharp_optimizer_dispose(adam);
563 }
564 }
565}