Skip to main content

torsh_ffi/
binding_generator.rs

1//! Binding Generator for ToRSh FFI
2//!
3//! This module provides tools to automatically generate FFI bindings for different programming languages
4//! based on the core ToRSh C API. It helps maintain consistency across language bindings and reduces
5//! the manual effort required to add support for new languages.
6
7#![allow(dead_code)]
8
9use crate::error::{FfiError, FfiResult};
10use std::collections::HashMap;
11use std::fmt::Write;
12
13/// Supported target languages for binding generation
14#[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/// Data type mapping for different languages
74#[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/// Function signature information
83#[derive(Debug, Clone)]
84pub struct FunctionSignature {
85    pub name: String,
86    pub return_type: String,
87    pub parameters: Vec<(String, String)>, // (name, type)
88    pub description: String,
89    pub is_unsafe: bool,
90}
91
92/// Binding generator for a specific target language
93pub 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                // Default C-style mappings
210                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        // Core tensor functions
477        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        // Tensor operations
516        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        // Module functions
548        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        // Optimizer functions
561        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        // Cleanup functions
582        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        // Add header
645        output.push_str(&self.header_template);
646        output.push('\n');
647
648        // Generate function bindings
649        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        // Add footer
656        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        // Function documentation
678        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        // Set up C function
687        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        // Function call
706        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        // Handle return value
716        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
951/// Generate bindings for a specific target language
952pub fn generate_bindings_for_language(target: TargetLanguage) -> FfiResult<String> {
953    let generator = BindingGenerator::new(target);
954    generator.generate_bindings()
955}
956
957/// Generate bindings for all supported languages
958pub 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}