1#![allow(dead_code)]
8
9use crate::error::{FfiError, FfiResult};
10use std::collections::HashMap;
11use std::fmt::Write;
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub enum TargetLanguage {
16 C,
17 CPlusPlus,
18 Python,
19 Ruby,
20 Java,
21 CSharp,
22 Go,
23 Swift,
24 R,
25 Julia,
26 Rust,
27 JavaScript,
28 TypeScript,
29 Kotlin,
30 Scala,
31}
32
33impl TargetLanguage {
34 pub fn file_extension(&self) -> &'static str {
35 match self {
36 TargetLanguage::C => "h",
37 TargetLanguage::CPlusPlus => "hpp",
38 TargetLanguage::Python => "py",
39 TargetLanguage::Ruby => "rb",
40 TargetLanguage::Java => "java",
41 TargetLanguage::CSharp => "cs",
42 TargetLanguage::Go => "go",
43 TargetLanguage::Swift => "swift",
44 TargetLanguage::R => "R",
45 TargetLanguage::Julia => "jl",
46 TargetLanguage::Rust => "rs",
47 TargetLanguage::JavaScript => "js",
48 TargetLanguage::TypeScript => "ts",
49 TargetLanguage::Kotlin => "kt",
50 TargetLanguage::Scala => "scala",
51 }
52 }
53
54 pub fn comment_prefix(&self) -> &'static str {
55 match self {
56 TargetLanguage::C
57 | TargetLanguage::CPlusPlus
58 | TargetLanguage::Java
59 | TargetLanguage::CSharp
60 | TargetLanguage::Go
61 | TargetLanguage::Swift
62 | TargetLanguage::Rust
63 | TargetLanguage::JavaScript
64 | TargetLanguage::TypeScript
65 | TargetLanguage::Kotlin
66 | TargetLanguage::Scala => "//",
67 TargetLanguage::Python | TargetLanguage::Ruby | TargetLanguage::R => "#",
68 TargetLanguage::Julia => "#",
69 }
70 }
71}
72
73#[derive(Debug, Clone)]
75pub struct TypeMapping {
76 pub c_type: String,
77 pub target_type: String,
78 pub conversion_from_c: Option<String>,
79 pub conversion_to_c: Option<String>,
80}
81
82#[derive(Debug, Clone)]
84pub struct FunctionSignature {
85 pub name: String,
86 pub return_type: String,
87 pub parameters: Vec<(String, String)>, pub description: String,
89 pub is_unsafe: bool,
90}
91
92pub struct BindingGenerator {
94 target_language: TargetLanguage,
95 type_mappings: HashMap<String, TypeMapping>,
96 functions: Vec<FunctionSignature>,
97 header_template: String,
98 footer_template: String,
99}
100
101impl BindingGenerator {
102 pub fn new(target_language: TargetLanguage) -> Self {
103 let mut generator = Self {
104 target_language,
105 type_mappings: HashMap::new(),
106 functions: Vec::new(),
107 header_template: String::new(),
108 footer_template: String::new(),
109 };
110
111 generator.initialize_type_mappings();
112 generator.initialize_templates();
113 generator.load_core_functions();
114
115 generator
116 }
117
118 fn initialize_type_mappings(&mut self) {
119 match self.target_language {
120 TargetLanguage::Python => {
121 self.add_type_mapping("c_int", "int", None, Some("ctypes.c_int".to_string()));
122 self.add_type_mapping("c_float", "float", None, Some("ctypes.c_float".to_string()));
123 self.add_type_mapping(
124 "c_double",
125 "float",
126 None,
127 Some("ctypes.c_double".to_string()),
128 );
129 self.add_type_mapping(
130 "c_char_p",
131 "str",
132 Some("s.decode('utf-8')".to_string()),
133 Some("s.encode('utf-8')".to_string()),
134 );
135 self.add_type_mapping("*mut TorshTensor", "TensorHandle", None, None);
136 self.add_type_mapping("*mut TorshModule", "ModuleHandle", None, None);
137 self.add_type_mapping("*mut TorshOptimizer", "OptimizerHandle", None, None);
138 }
139 TargetLanguage::Java => {
140 self.add_type_mapping("c_int", "int", None, None);
141 self.add_type_mapping("c_float", "float", None, None);
142 self.add_type_mapping("c_double", "double", None, None);
143 self.add_type_mapping("c_char_p", "String", None, None);
144 self.add_type_mapping("*mut TorshTensor", "long", None, None);
145 self.add_type_mapping("*mut TorshModule", "long", None, None);
146 self.add_type_mapping("*mut TorshOptimizer", "long", None, None);
147 }
148 TargetLanguage::CSharp => {
149 self.add_type_mapping("c_int", "int", None, None);
150 self.add_type_mapping("c_float", "float", None, None);
151 self.add_type_mapping("c_double", "double", None, None);
152 self.add_type_mapping("c_char_p", "string", None, None);
153 self.add_type_mapping("*mut TorshTensor", "IntPtr", None, None);
154 self.add_type_mapping("*mut TorshModule", "IntPtr", None, None);
155 self.add_type_mapping("*mut TorshOptimizer", "IntPtr", None, None);
156 }
157 TargetLanguage::Go => {
158 self.add_type_mapping("c_int", "C.int", None, None);
159 self.add_type_mapping("c_float", "C.float", None, None);
160 self.add_type_mapping("c_double", "C.double", None, None);
161 self.add_type_mapping(
162 "c_char_p",
163 "*C.char",
164 Some("C.GoString(s)".to_string()),
165 Some("C.CString(s)".to_string()),
166 );
167 self.add_type_mapping("*mut TorshTensor", "unsafe.Pointer", None, None);
168 self.add_type_mapping("*mut TorshModule", "unsafe.Pointer", None, None);
169 self.add_type_mapping("*mut TorshOptimizer", "unsafe.Pointer", None, None);
170 }
171 TargetLanguage::Swift => {
172 self.add_type_mapping("c_int", "Int32", None, None);
173 self.add_type_mapping("c_float", "Float", None, None);
174 self.add_type_mapping("c_double", "Double", None, None);
175 self.add_type_mapping(
176 "c_char_p",
177 "String",
178 Some("String(cString: s)".to_string()),
179 Some("s.withCString".to_string()),
180 );
181 self.add_type_mapping("*mut TorshTensor", "OpaquePointer", None, None);
182 self.add_type_mapping("*mut TorshModule", "OpaquePointer", None, None);
183 self.add_type_mapping("*mut TorshOptimizer", "OpaquePointer", None, None);
184 }
185 TargetLanguage::R => {
186 self.add_type_mapping("c_int", "integer", None, Some("as.integer".to_string()));
187 self.add_type_mapping("c_float", "numeric", None, Some("as.numeric".to_string()));
188 self.add_type_mapping("c_double", "numeric", None, Some("as.double".to_string()));
189 self.add_type_mapping(
190 "c_char_p",
191 "character",
192 None,
193 Some("as.character".to_string()),
194 );
195 self.add_type_mapping("*mut TorshTensor", "externalptr", None, None);
196 self.add_type_mapping("*mut TorshModule", "externalptr", None, None);
197 self.add_type_mapping("*mut TorshOptimizer", "externalptr", None, None);
198 }
199 TargetLanguage::Julia => {
200 self.add_type_mapping("c_int", "Cint", None, None);
201 self.add_type_mapping("c_float", "Cfloat", None, None);
202 self.add_type_mapping("c_double", "Cdouble", None, None);
203 self.add_type_mapping("c_char_p", "Cstring", None, None);
204 self.add_type_mapping("*mut TorshTensor", "Ptr{Cvoid}", None, None);
205 self.add_type_mapping("*mut TorshModule", "Ptr{Cvoid}", None, None);
206 self.add_type_mapping("*mut TorshOptimizer", "Ptr{Cvoid}", None, None);
207 }
208 _ => {
209 self.add_type_mapping("c_int", "int", None, None);
211 self.add_type_mapping("c_float", "float", None, None);
212 self.add_type_mapping("c_double", "double", None, None);
213 self.add_type_mapping("c_char_p", "char*", None, None);
214 self.add_type_mapping("*mut TorshTensor", "void*", None, None);
215 self.add_type_mapping("*mut TorshModule", "void*", None, None);
216 self.add_type_mapping("*mut TorshOptimizer", "void*", None, None);
217 }
218 }
219 }
220
221 fn initialize_templates(&mut self) {
222 match self.target_language {
223 TargetLanguage::Python => {
224 self.header_template = r#""""
225ToRSh Python Bindings (Auto-generated)
226
227This module provides Python bindings for the ToRSh deep learning framework.
228Generated automatically from the C API.
229"""
230
231import ctypes
232from ctypes import c_int, c_float, c_double, c_char_p, c_void_p, POINTER
233from typing import Optional, Union, List, Tuple
234import numpy as np
235
236# Load the ToRSh shared library
237_lib = ctypes.CDLL("./libtorsh_ffi.so") # Adjust path as needed
238
239class TorshError(Exception):
240 """Exception raised for ToRSh errors."""
241 pass
242
243class TensorHandle:
244 """Handle to a ToRSh tensor."""
245 def __init__(self, ptr: c_void_p):
246 self.ptr = ptr
247
248 def __del__(self):
249 if hasattr(self, 'ptr') and self.ptr:
250 _lib.torsh_tensor_free(self.ptr)
251
252class ModuleHandle:
253 """Handle to a ToRSh module."""
254 def __init__(self, ptr: c_void_p):
255 self.ptr = ptr
256
257 def __del__(self):
258 if hasattr(self, 'ptr') and self.ptr:
259 _lib.torsh_module_free(self.ptr)
260
261class OptimizerHandle:
262 """Handle to a ToRSh optimizer."""
263 def __init__(self, ptr: c_void_p):
264 self.ptr = ptr
265
266 def __del__(self):
267 if hasattr(self, 'ptr') and self.ptr:
268 _lib.torsh_optimizer_free(self.ptr)
269
270"#
271 .to_string();
272
273 self.footer_template = r#"
274def get_last_error() -> Optional[str]:
275 """Get the last error message from ToRSh."""
276 buffer = ctypes.create_string_buffer(1024)
277 result = _lib.torsh_get_last_error(buffer, 1024)
278 if result > 0:
279 return buffer.value.decode('utf-8')
280 return None
281
282def clear_last_error():
283 """Clear the last error message."""
284 _lib.torsh_clear_last_error()
285"#
286 .to_string();
287 }
288 TargetLanguage::Java => {
289 self.header_template = r#"/**
290 * ToRSh Java Bindings (Auto-generated)
291 *
292 * This class provides Java bindings for the ToRSh deep learning framework.
293 * Generated automatically from the C API.
294 */
295
296package com.torsh.ffi;
297
298public class TorshBindings {
299 static {
300 System.loadLibrary("torsh_ffi"); // Load native library
301 }
302
303 // Error codes
304 public static final int TORSH_SUCCESS = 0;
305 public static final int TORSH_ERROR_INVALID_ARGUMENT = 1;
306 public static final int TORSH_ERROR_SHAPE_MISMATCH = 2;
307 public static final int TORSH_ERROR_RUNTIME_ERROR = 3;
308
309 /**
310 * Exception for ToRSh errors.
311 */
312 public static class TorshException extends Exception {
313 public TorshException(String message) {
314 super(message);
315 }
316 }
317
318 /**
319 * Handle to a ToRSh tensor.
320 */
321 public static class TensorHandle {
322 private long ptr;
323
324 public TensorHandle(long ptr) {
325 this.ptr = ptr;
326 }
327
328 public long getPtr() {
329 return ptr;
330 }
331
332 @Override
333 protected void finalize() throws Throwable {
334 if (ptr != 0) {
335 tensorFree(ptr);
336 ptr = 0;
337 }
338 super.finalize();
339 }
340 }
341
342"#
343 .to_string();
344
345 self.footer_template = r#"
346 /**
347 * Get the last error message from ToRSh.
348 */
349 public static native String getLastError();
350
351 /**
352 * Clear the last error message.
353 */
354 public static native void clearLastError();
355
356 // Native method declarations will be inserted here by the generator
357}
358"#
359 .to_string();
360 }
361 TargetLanguage::Go => {
362 self.header_template = r#"// ToRSh Go Bindings (Auto-generated)
363//
364// This package provides Go bindings for the ToRSh deep learning framework.
365// Generated automatically from the C API.
366
367package torsh
368
369/*
370#cgo LDFLAGS: -ltorsh_ffi
371#include <stdlib.h>
372#include <string.h>
373
374// Include ToRSh C API headers here
375// #include "torsh_ffi.h"
376*/
377import "C"
378import (
379 "errors"
380 "runtime"
381 "unsafe"
382)
383
384// Error definitions
385var (
386 ErrInvalidArgument = errors.New("invalid argument")
387 ErrShapeMismatch = errors.New("shape mismatch")
388 ErrRuntimeError = errors.New("runtime error")
389)
390
391// TensorHandle wraps a ToRSh tensor pointer
392type TensorHandle struct {
393 ptr unsafe.Pointer
394}
395
396// NewTensorHandle creates a new tensor handle
397func NewTensorHandle(ptr unsafe.Pointer) *TensorHandle {
398 h := &TensorHandle{ptr: ptr}
399 runtime.SetFinalizer(h, (*TensorHandle).free)
400 return h
401}
402
403// Ptr returns the underlying C pointer
404func (h *TensorHandle) Ptr() unsafe.Pointer {
405 return h.ptr
406}
407
408// free releases the tensor
409func (h *TensorHandle) free() {
410 if h.ptr != nil {
411 C.torsh_tensor_free(h.ptr)
412 h.ptr = nil
413 }
414}
415
416// ModuleHandle wraps a ToRSh module pointer
417type ModuleHandle struct {
418 ptr unsafe.Pointer
419}
420
421// NewModuleHandle creates a new module handle
422func NewModuleHandle(ptr unsafe.Pointer) *ModuleHandle {
423 h := &ModuleHandle{ptr: ptr}
424 runtime.SetFinalizer(h, (*ModuleHandle).free)
425 return h
426}
427
428// Ptr returns the underlying C pointer
429func (h *ModuleHandle) Ptr() unsafe.Pointer {
430 return h.ptr
431}
432
433// free releases the module
434func (h *ModuleHandle) free() {
435 if h.ptr != nil {
436 C.torsh_module_free(h.ptr)
437 h.ptr = nil
438 }
439}
440
441"#
442 .to_string();
443
444 self.footer_template = r#"
445// GetLastError returns the last error message from ToRSh
446func GetLastError() string {
447 buffer := make([]byte, 1024)
448 result := C.torsh_get_last_error((*C.char)(unsafe.Pointer(&buffer[0])), C.int(len(buffer)))
449 if result > 0 {
450 return string(buffer[:result])
451 }
452 return ""
453}
454
455// ClearLastError clears the last error message
456func ClearLastError() {
457 C.torsh_clear_last_error()
458}
459"#
460 .to_string();
461 }
462 _ => {
463 self.header_template = format!(
464 "{} Auto-generated ToRSh bindings\n",
465 self.target_language.comment_prefix()
466 );
467 self.footer_template = format!(
468 "{} End of auto-generated bindings\n",
469 self.target_language.comment_prefix()
470 );
471 }
472 }
473 }
474
475 fn load_core_functions(&mut self) {
476 self.add_function(
478 "torsh_tensor_new",
479 "TorshTensor*",
480 vec![],
481 "Create a new empty tensor".to_string(),
482 true,
483 );
484 self.add_function(
485 "torsh_tensor_zeros",
486 "TorshTensor*",
487 vec![
488 ("shape".to_string(), "*const c_int".to_string()),
489 ("shape_len".to_string(), "c_int".to_string()),
490 ],
491 "Create a tensor filled with zeros".to_string(),
492 true,
493 );
494 self.add_function(
495 "torsh_tensor_ones",
496 "TorshTensor*",
497 vec![
498 ("shape".to_string(), "*const c_int".to_string()),
499 ("shape_len".to_string(), "c_int".to_string()),
500 ],
501 "Create a tensor filled with ones".to_string(),
502 true,
503 );
504 self.add_function(
505 "torsh_tensor_randn",
506 "TorshTensor*",
507 vec![
508 ("shape".to_string(), "*const c_int".to_string()),
509 ("shape_len".to_string(), "c_int".to_string()),
510 ],
511 "Create a tensor with random normal distribution".to_string(),
512 true,
513 );
514
515 self.add_function(
517 "torsh_tensor_add",
518 "TorshTensor*",
519 vec![
520 ("a".to_string(), "*mut TorshTensor".to_string()),
521 ("b".to_string(), "*mut TorshTensor".to_string()),
522 ],
523 "Add two tensors".to_string(),
524 true,
525 );
526 self.add_function(
527 "torsh_tensor_mul",
528 "TorshTensor*",
529 vec![
530 ("a".to_string(), "*mut TorshTensor".to_string()),
531 ("b".to_string(), "*mut TorshTensor".to_string()),
532 ],
533 "Multiply two tensors element-wise".to_string(),
534 true,
535 );
536 self.add_function(
537 "torsh_tensor_matmul",
538 "TorshTensor*",
539 vec![
540 ("a".to_string(), "*mut TorshTensor".to_string()),
541 ("b".to_string(), "*mut TorshTensor".to_string()),
542 ],
543 "Matrix multiplication".to_string(),
544 true,
545 );
546
547 self.add_function(
549 "torsh_linear_create",
550 "TorshModule*",
551 vec![
552 ("in_features".to_string(), "c_int".to_string()),
553 ("out_features".to_string(), "c_int".to_string()),
554 ("bias".to_string(), "bool".to_string()),
555 ],
556 "Create a linear layer".to_string(),
557 true,
558 );
559
560 self.add_function(
562 "torsh_sgd_create",
563 "TorshOptimizer*",
564 vec![("learning_rate".to_string(), "c_float".to_string())],
565 "Create SGD optimizer".to_string(),
566 true,
567 );
568 self.add_function(
569 "torsh_adam_create",
570 "TorshOptimizer*",
571 vec![
572 ("learning_rate".to_string(), "c_float".to_string()),
573 ("beta1".to_string(), "c_float".to_string()),
574 ("beta2".to_string(), "c_float".to_string()),
575 ("epsilon".to_string(), "c_float".to_string()),
576 ],
577 "Create Adam optimizer".to_string(),
578 true,
579 );
580
581 self.add_function(
583 "torsh_tensor_free",
584 "void",
585 vec![("tensor".to_string(), "*mut TorshTensor".to_string())],
586 "Free a tensor".to_string(),
587 true,
588 );
589 self.add_function(
590 "torsh_module_free",
591 "void",
592 vec![("module".to_string(), "*mut TorshModule".to_string())],
593 "Free a module".to_string(),
594 true,
595 );
596 self.add_function(
597 "torsh_optimizer_free",
598 "void",
599 vec![("optimizer".to_string(), "*mut TorshOptimizer".to_string())],
600 "Free an optimizer".to_string(),
601 true,
602 );
603 }
604
605 fn add_type_mapping(
606 &mut self,
607 c_type: &str,
608 target_type: &str,
609 conversion_from_c: Option<String>,
610 conversion_to_c: Option<String>,
611 ) {
612 self.type_mappings.insert(
613 c_type.to_string(),
614 TypeMapping {
615 c_type: c_type.to_string(),
616 target_type: target_type.to_string(),
617 conversion_from_c,
618 conversion_to_c,
619 },
620 );
621 }
622
623 #[allow(clippy::too_many_arguments)]
624 fn add_function(
625 &mut self,
626 name: &str,
627 return_type: &str,
628 parameters: Vec<(String, String)>,
629 description: String,
630 is_unsafe: bool,
631 ) {
632 self.functions.push(FunctionSignature {
633 name: name.to_string(),
634 return_type: return_type.to_string(),
635 parameters,
636 description,
637 is_unsafe,
638 });
639 }
640
641 pub fn generate_bindings(&self) -> FfiResult<String> {
642 let mut output = String::new();
643
644 output.push_str(&self.header_template);
646 output.push('\n');
647
648 for func in &self.functions {
650 let binding = self.generate_function_binding(func)?;
651 output.push_str(&binding);
652 output.push('\n');
653 }
654
655 output.push_str(&self.footer_template);
657
658 Ok(output)
659 }
660
661 fn generate_function_binding(&self, func: &FunctionSignature) -> FfiResult<String> {
662 match self.target_language {
663 TargetLanguage::Python => self.generate_python_function(func),
664 TargetLanguage::Java => self.generate_java_function(func),
665 TargetLanguage::Go => self.generate_go_function(func),
666 TargetLanguage::CSharp => self.generate_csharp_function(func),
667 TargetLanguage::Swift => self.generate_swift_function(func),
668 _ => Err(FfiError::UnsupportedOperation {
669 operation: format!("Function generation for {:?}", self.target_language),
670 }),
671 }
672 }
673
674 fn generate_python_function(&self, func: &FunctionSignature) -> FfiResult<String> {
675 let mut output = String::new();
676
677 writeln!(
679 output,
680 "def {}({}):",
681 self.convert_function_name(&func.name),
682 self.convert_parameters_python(&func.parameters)
683 )?;
684 writeln!(output, " \"\"\"{}\"\"\"", func.description)?;
685
686 writeln!(
688 output,
689 " _lib.{}.restype = {}",
690 func.name,
691 self.convert_type_python(&func.return_type)
692 )?;
693
694 if !func.parameters.is_empty() {
695 write!(output, " _lib.{}.argtypes = [", func.name)?;
696 for (i, (_, param_type)) in func.parameters.iter().enumerate() {
697 if i > 0 {
698 write!(output, ", ")?;
699 }
700 write!(output, "{}", self.convert_type_python(param_type))?;
701 }
702 writeln!(output, "]")?;
703 }
704
705 write!(output, " result = _lib.{}(", func.name)?;
707 for (i, (param_name, _)) in func.parameters.iter().enumerate() {
708 if i > 0 {
709 write!(output, ", ")?;
710 }
711 write!(output, "{}", param_name)?;
712 }
713 writeln!(output, ")")?;
714
715 if func.return_type != "void" {
717 writeln!(output, " return result")?;
718 }
719
720 Ok(output)
721 }
722
723 fn generate_java_function(&self, func: &FunctionSignature) -> FfiResult<String> {
724 let mut output = String::new();
725
726 writeln!(output, " /**")?;
727 writeln!(output, " * {}", func.description)?;
728 writeln!(output, " */")?;
729
730 write!(
731 output,
732 " public static native {} {}(",
733 self.convert_type_java(&func.return_type),
734 self.convert_function_name(&func.name)
735 )?;
736
737 for (i, (param_name, param_type)) in func.parameters.iter().enumerate() {
738 if i > 0 {
739 write!(output, ", ")?;
740 }
741 write!(
742 output,
743 "{} {}",
744 self.convert_type_java(param_type),
745 param_name
746 )?;
747 }
748
749 writeln!(output, ");")?;
750
751 Ok(output)
752 }
753
754 fn generate_go_function(&self, func: &FunctionSignature) -> FfiResult<String> {
755 let mut output = String::new();
756
757 writeln!(
758 output,
759 "// {} - {}",
760 self.convert_function_name(&func.name),
761 func.description
762 )?;
763
764 write!(output, "func {}(", self.convert_function_name(&func.name))?;
765 for (i, (param_name, param_type)) in func.parameters.iter().enumerate() {
766 if i > 0 {
767 write!(output, ", ")?;
768 }
769 write!(
770 output,
771 "{} {}",
772 param_name,
773 self.convert_type_go(param_type)
774 )?;
775 }
776 write!(output, ") ")?;
777
778 if func.return_type != "void" {
779 write!(output, "{} ", self.convert_type_go(&func.return_type))?;
780 }
781
782 writeln!(output, "{{")?;
783 write!(output, " return C.{}(", func.name)?;
784 for (i, (param_name, _)) in func.parameters.iter().enumerate() {
785 if i > 0 {
786 write!(output, ", ")?;
787 }
788 write!(output, "{}", param_name)?;
789 }
790 writeln!(output, ")")?;
791 writeln!(output, "}}")?;
792
793 Ok(output)
794 }
795
796 fn generate_csharp_function(&self, func: &FunctionSignature) -> FfiResult<String> {
797 let mut output = String::new();
798
799 writeln!(output, " /// <summary>")?;
800 writeln!(output, " /// {}", func.description)?;
801 writeln!(output, " /// </summary>")?;
802
803 writeln!(output, " [DllImport(\"torsh_ffi\")]")?;
804 write!(
805 output,
806 " public static extern {} {}(",
807 self.convert_type_csharp(&func.return_type),
808 self.convert_function_name(&func.name)
809 )?;
810
811 for (i, (param_name, param_type)) in func.parameters.iter().enumerate() {
812 if i > 0 {
813 write!(output, ", ")?;
814 }
815 write!(
816 output,
817 "{} {}",
818 self.convert_type_csharp(param_type),
819 param_name
820 )?;
821 }
822
823 writeln!(output, ");")?;
824
825 Ok(output)
826 }
827
828 fn generate_swift_function(&self, func: &FunctionSignature) -> FfiResult<String> {
829 let mut output = String::new();
830
831 writeln!(output, "/// {}", func.description)?;
832
833 write!(output, "func {}(", self.convert_function_name(&func.name))?;
834 for (i, (param_name, param_type)) in func.parameters.iter().enumerate() {
835 if i > 0 {
836 write!(output, ", ")?;
837 }
838 write!(
839 output,
840 "{}: {}",
841 param_name,
842 self.convert_type_swift(param_type)
843 )?;
844 }
845 write!(output, ")")?;
846
847 if func.return_type != "void" {
848 write!(output, " -> {}", self.convert_type_swift(&func.return_type))?;
849 }
850
851 writeln!(output, " {{")?;
852 write!(output, " return {}(", func.name)?;
853 for (i, (param_name, _)) in func.parameters.iter().enumerate() {
854 if i > 0 {
855 write!(output, ", ")?;
856 }
857 write!(output, "{}", param_name)?;
858 }
859 writeln!(output, ")")?;
860 writeln!(output, "}}")?;
861
862 Ok(output)
863 }
864
865 fn convert_function_name(&self, name: &str) -> String {
866 match self.target_language {
867 TargetLanguage::Python => name.replace("torsh_", "").replace("_", "_"),
868 TargetLanguage::Java | TargetLanguage::CSharp => {
869 let without_prefix = name.strip_prefix("torsh_").unwrap_or(name);
870 self.to_camel_case(without_prefix)
871 }
872 TargetLanguage::Go => {
873 let without_prefix = name.strip_prefix("torsh_").unwrap_or(name);
874 self.to_pascal_case(without_prefix)
875 }
876 _ => name.to_string(),
877 }
878 }
879
880 fn convert_parameters_python(&self, params: &[(String, String)]) -> String {
881 params
882 .iter()
883 .map(|(name, _)| name.clone())
884 .collect::<Vec<_>>()
885 .join(", ")
886 }
887
888 fn convert_type_python(&self, c_type: &str) -> String {
889 self.type_mappings
890 .get(c_type)
891 .map(|mapping| mapping.target_type.clone())
892 .unwrap_or_else(|| "c_void_p".to_string())
893 }
894
895 fn convert_type_java(&self, c_type: &str) -> String {
896 self.type_mappings
897 .get(c_type)
898 .map(|mapping| mapping.target_type.clone())
899 .unwrap_or_else(|| "long".to_string())
900 }
901
902 fn convert_type_go(&self, c_type: &str) -> String {
903 self.type_mappings
904 .get(c_type)
905 .map(|mapping| mapping.target_type.clone())
906 .unwrap_or_else(|| "unsafe.Pointer".to_string())
907 }
908
909 fn convert_type_csharp(&self, c_type: &str) -> String {
910 self.type_mappings
911 .get(c_type)
912 .map(|mapping| mapping.target_type.clone())
913 .unwrap_or_else(|| "IntPtr".to_string())
914 }
915
916 fn convert_type_swift(&self, c_type: &str) -> String {
917 self.type_mappings
918 .get(c_type)
919 .map(|mapping| mapping.target_type.clone())
920 .unwrap_or_else(|| "OpaquePointer".to_string())
921 }
922
923 fn to_camel_case(&self, s: &str) -> String {
924 let mut result = String::new();
925 let mut capitalize_next = false;
926
927 for ch in s.chars() {
928 if ch == '_' {
929 capitalize_next = true;
930 } else if capitalize_next {
931 result.push(ch.to_uppercase().next().unwrap_or(ch));
932 capitalize_next = false;
933 } else {
934 result.push(ch);
935 }
936 }
937
938 result
939 }
940
941 fn to_pascal_case(&self, s: &str) -> String {
942 let camel_case = self.to_camel_case(s);
943 if let Some(first_char) = camel_case.chars().next() {
944 first_char.to_uppercase().collect::<String>() + &camel_case[1..]
945 } else {
946 camel_case
947 }
948 }
949}
950
951pub fn generate_bindings_for_language(target: TargetLanguage) -> FfiResult<String> {
953 let generator = BindingGenerator::new(target);
954 generator.generate_bindings()
955}
956
957pub fn generate_all_bindings() -> FfiResult<HashMap<TargetLanguage, String>> {
959 let languages = vec![
960 TargetLanguage::Python,
961 TargetLanguage::Java,
962 TargetLanguage::Go,
963 TargetLanguage::CSharp,
964 TargetLanguage::Swift,
965 TargetLanguage::R,
966 TargetLanguage::Julia,
967 ];
968
969 let mut results = HashMap::new();
970
971 for lang in languages {
972 let bindings = generate_bindings_for_language(lang.clone())?;
973 results.insert(lang, bindings);
974 }
975
976 Ok(results)
977}
978
979#[cfg(test)]
980mod tests {
981 use super::*;
982
983 #[test]
984 fn test_target_language_properties() {
985 assert_eq!(TargetLanguage::Python.file_extension(), "py");
986 assert_eq!(TargetLanguage::Python.comment_prefix(), "#");
987 assert_eq!(TargetLanguage::Java.file_extension(), "java");
988 assert_eq!(TargetLanguage::Java.comment_prefix(), "//");
989 }
990
991 #[test]
992 fn test_binding_generator_creation() {
993 let generator = BindingGenerator::new(TargetLanguage::Python);
994 assert!(!generator.type_mappings.is_empty());
995 assert!(!generator.functions.is_empty());
996 }
997
998 #[test]
999 fn test_function_name_conversion() {
1000 let generator = BindingGenerator::new(TargetLanguage::Java);
1001 assert_eq!(
1002 generator.convert_function_name("torsh_tensor_add"),
1003 "tensorAdd"
1004 );
1005
1006 let generator = BindingGenerator::new(TargetLanguage::Go);
1007 assert_eq!(
1008 generator.convert_function_name("torsh_tensor_add"),
1009 "TensorAdd"
1010 );
1011 }
1012
1013 #[test]
1014 fn test_case_conversion() {
1015 let generator = BindingGenerator::new(TargetLanguage::Java);
1016 assert_eq!(generator.to_camel_case("tensor_add"), "tensorAdd");
1017 assert_eq!(generator.to_pascal_case("tensor_add"), "TensorAdd");
1018 }
1019
1020 #[test]
1021 fn test_type_mapping() {
1022 let generator = BindingGenerator::new(TargetLanguage::Python);
1023 assert_eq!(generator.convert_type_python("c_int"), "int");
1024 assert_eq!(
1025 generator.convert_type_python("*mut TorshTensor"),
1026 "TensorHandle"
1027 );
1028 }
1029
1030 #[test]
1031 fn test_python_binding_generation() {
1032 let generator = BindingGenerator::new(TargetLanguage::Python);
1033 let bindings = generator.generate_bindings();
1034 assert!(bindings.is_ok());
1035
1036 let content = bindings.unwrap();
1037 assert!(content.contains("import ctypes"));
1038 assert!(content.contains("def tensor_add"));
1039 }
1040}