use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone)]
pub struct CExternFunction {
pub name: String,
pub return_type: String,
pub params: Vec<(String, String)>,
pub is_variadic: bool,
}
impl CExternFunction {
pub fn new(name: &str, return_type: &str) -> Self {
Self {
name: name.to_string(),
return_type: return_type.to_string(),
params: Vec::new(),
is_variadic: false,
}
}
pub fn add_param(&mut self, name: &str, ty: &str) {
self.params.push((name.to_string(), ty.to_string()));
}
pub fn to_extern_c(&self) -> String {
let params_str: Vec<String> = self
.params
.iter()
.map(|(n, t)| format!("{} {}", t, n))
.collect();
let variadic = if self.is_variadic { ", ..." } else { "" };
format!(
"extern \"C\" {} {}({}{});",
self.return_type,
self.name,
params_str.join(", "),
variadic
)
}
pub fn to_c_header(&self) -> String {
let params_str: Vec<String> = self
.params
.iter()
.map(|(n, t)| format!("{} {}", t, n))
.collect();
let variadic = if self.is_variadic { ", ..." } else { "" };
format!(
"{} {}({}{});",
self.return_type,
self.name,
params_str.join(", "),
variadic
)
}
pub fn to_llvm_declare(&self) -> String {
let ret_ty = ctype_to_llvm(&self.return_type);
let param_tys: Vec<String> = self.params.iter().map(|(_, t)| ctype_to_llvm(t)).collect();
let variadic = if self.is_variadic { ", ..." } else { "" };
format!(
"declare {} @{}({}{})",
ret_ty,
self.name,
param_tys.join(", "),
variadic
)
}
}
pub fn ctype_to_llvm(ct: &str) -> String {
match ct {
"void" => "void".into(),
"char" | "signed char" | "unsigned char" => "i8".into(),
"short" | "unsigned short" => "i16".into(),
"int" | "unsigned int" => "i32".into(),
"long" | "unsigned long" | "long long" | "unsigned long long" => "i64".into(),
"float" => "float".into(),
"double" => "double".into(),
"long double" => "fp128".into(),
"bool" | "_Bool" => "i1".into(),
s if s.ends_with('*') => "ptr".into(),
_ => "ptr".into(),
}
}
#[derive(Debug, Clone)]
pub struct CXXExternFunction {
pub function: CExternFunction,
pub mangled_name: String,
pub exception_spec: ExceptionSpec,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExceptionSpec {
None,
Noexcept,
Throw,
ThrowTypes(Vec<String>),
}
impl CXXExternFunction {
pub fn new(name: &str, return_type: &str) -> Self {
Self {
function: CExternFunction::new(name, return_type),
mangled_name: String::new(),
exception_spec: ExceptionSpec::None,
}
}
pub fn extern_c_declaration(&self) -> String {
format!("extern \"C\" {{ {} }}", self.function.to_c_header())
}
}
#[derive(Debug, Clone)]
pub struct ObjCInterface {
pub name: String,
pub superclass: Option<String>,
pub instance_variables: Vec<(String, String)>,
pub properties: Vec<ObjCProperty>,
pub methods: Vec<ObjCMethod>,
pub protocols: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ObjCProperty {
pub name: String,
pub ty: String,
pub attributes: Vec<ObjCPropertyAttr>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ObjCPropertyAttr {
Nonatomic,
Atomic,
Strong,
Weak,
Copy,
Assign,
Readonly,
Readwrite,
Getter(String),
Setter(String),
}
#[derive(Debug, Clone)]
pub struct ObjCMethod {
pub is_class_method: bool,
pub selector: String,
pub return_type: String,
pub params: Vec<(String, String, String)>, }
impl ObjCInterface {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
superclass: None,
instance_variables: Vec::new(),
properties: Vec::new(),
methods: Vec::new(),
protocols: Vec::new(),
}
}
pub fn to_interface_declaration(&self) -> String {
let super_part = if let Some(ref sup) = self.superclass {
format!(" : {}", sup)
} else {
String::new()
};
let proto_part = if self.protocols.is_empty() {
String::new()
} else {
format!(" <{}>", self.protocols.join(", "))
};
format!("@interface {}{}{}\n@end", self.name, super_part, proto_part)
}
pub fn add_message_send(&self, target: &str, method: &ObjCMethod) -> String {
if method.is_class_method {
format!("[{} {}]", target, method.selector)
} else {
format!("[{} {}]", target, method.selector)
}
}
}
#[derive(Debug, Clone)]
pub struct ObjCMessageSend {
pub target: String,
pub selector: String,
pub arguments: Vec<String>,
}
impl ObjCMessageSend {
pub fn new(target: &str, selector: &str) -> Self {
Self {
target: target.to_string(),
selector: selector.to_string(),
arguments: Vec::new(),
}
}
pub fn to_objc(&self) -> String {
if self.arguments.is_empty() {
format!("[{} {}]", self.target, self.selector)
} else {
let parts: Vec<&str> = self.selector.split(':').collect();
let mut out = format!("[{} ", self.target);
for (i, arg) in self.arguments.iter().enumerate() {
if i < parts.len() {
out.push_str(&format!("{}:{} ", parts[i], arg));
}
}
out.push(']');
out
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CudaFunctionKind {
Global,
Device,
Host,
HostDevice,
}
impl fmt::Display for CudaFunctionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Global => write!(f, "__global__"),
Self::Device => write!(f, "__device__"),
Self::Host => write!(f, "__host__"),
Self::HostDevice => write!(f, "__host__ __device__"),
}
}
}
#[derive(Debug, Clone)]
pub struct CudaKernel {
pub name: String,
pub kind: CudaFunctionKind,
pub params: Vec<(String, String)>,
pub grid_dim: (u32, u32, u32),
pub block_dim: (u32, u32, u32),
pub shared_memory_bytes: usize,
}
impl CudaKernel {
pub fn new(name: &str, kind: CudaFunctionKind) -> Self {
Self {
name: name.to_string(),
kind,
params: Vec::new(),
grid_dim: (1, 1, 1),
block_dim: (1, 1, 1),
shared_memory_bytes: 0,
}
}
pub fn to_launch_syntax(&self) -> String {
format!(
"{}<<<dim3({},{},{}), dim3({},{},{}), {}>>>",
self.name,
self.grid_dim.0,
self.grid_dim.1,
self.grid_dim.2,
self.block_dim.0,
self.block_dim.1,
self.block_dim.2,
self.shared_memory_bytes
)
}
pub fn to_declaration(&self) -> String {
let params_str: Vec<String> = self
.params
.iter()
.map(|(n, t)| format!("{} {}", t, n))
.collect();
format!(
"{} void {}({})",
self.kind,
self.name,
params_str.join(", ")
)
}
pub fn to_runtime_launch(&self) -> String {
format!(
"cudaLaunchKernel((void*){}, dim3({},{},{}), dim3({},{},{}), \
nullptr, {}, nullptr)",
self.name,
self.grid_dim.0,
self.grid_dim.1,
self.grid_dim.2,
self.block_dim.0,
self.block_dim.1,
self.block_dim.2,
self.shared_memory_bytes
)
}
}
#[derive(Debug, Clone)]
pub struct CudaMemory {
pub name: String,
pub space: CudaMemorySpace,
pub size: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CudaMemorySpace {
Global,
Shared,
Constant,
Local,
Texture,
Surface,
Managed,
Unified,
}
impl CudaMemorySpace {
pub fn qualifier(&self) -> &'static str {
match self {
Self::Global => "__device__",
Self::Shared => "__shared__",
Self::Constant => "__constant__",
Self::Local | Self::Texture | Self::Surface => "__device__",
Self::Managed => "__managed__",
Self::Unified => "",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpenCLAddressSpace {
Global,
Local,
Constant,
Private,
Generic,
}
impl OpenCLAddressSpace {
pub fn qualifier(&self) -> &'static str {
match self {
Self::Global => "__global",
Self::Local => "__local",
Self::Constant => "__constant",
Self::Private => "__private",
Self::Generic => "__generic",
}
}
}
#[derive(Debug, Clone)]
pub struct OpenCLKernel {
pub name: String,
pub params: Vec<(String, String, OpenCLAddressSpace)>,
pub work_group_size_hint: Option<(usize, usize, usize)>,
pub reqd_work_group_size: Option<(usize, usize, usize)>,
}
impl OpenCLKernel {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
params: Vec::new(),
work_group_size_hint: None,
reqd_work_group_size: None,
}
}
pub fn to_declaration(&self) -> String {
let params_str: Vec<String> = self
.params
.iter()
.map(|(n, t, space)| format!("{} {} {}", space.qualifier(), t, n))
.collect();
let attrs = if let Some((x, y, z)) = self.reqd_work_group_size {
format!(
"__attribute__((reqd_work_group_size({}, {}, {})))\n",
x, y, z
)
} else {
String::new()
};
format!(
"{}__kernel void {}({})",
attrs,
self.name,
params_str.join(", ")
)
}
pub fn to_enqueue_call(
&self,
queue: &str,
global_size: (usize, usize, usize),
local_size: Option<(usize, usize, usize)>,
) -> String {
let local = if let Some((x, y, z)) = local_size {
format!(", size_t[3]{{{}, {}, {}}}", x, y, z)
} else {
", nullptr".to_string()
};
format!(
"clEnqueueNDRangeKernel({}, kernel_{}, 3, nullptr, \
size_t[3]{{{}, {}, {}}}{}, 0, nullptr, nullptr)",
queue, self.name, global_size.0, global_size.1, global_size.2, local
)
}
}
#[derive(Debug, Clone)]
pub struct SyclQueue {
pub name: String,
pub device_selector: SyclDeviceSelector,
}
#[derive(Debug, Clone)]
pub enum SyclDeviceSelector {
DefaultSelector,
GpuSelector,
CpuSelector,
AcceleratorSelector,
Custom(String),
}
impl SyclQueue {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
device_selector: SyclDeviceSelector::DefaultSelector,
}
}
pub fn to_declaration(&self) -> String {
let selector = match &self.device_selector {
SyclDeviceSelector::DefaultSelector => "default_selector",
SyclDeviceSelector::GpuSelector => "gpu_selector",
SyclDeviceSelector::CpuSelector => "cpu_selector",
SyclDeviceSelector::AcceleratorSelector => "accelerator_selector",
SyclDeviceSelector::Custom(s) => s,
};
format!("sycl::queue {} ({})", self.name, selector)
}
}
#[derive(Debug, Clone)]
pub struct SyclBuffer {
pub name: String,
pub element_type: String,
pub size: usize,
pub access_mode: SyclAccessMode,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SyclAccessMode {
Read,
Write,
ReadWrite,
DiscardWrite,
DiscardReadWrite,
}
impl SyclBuffer {
pub fn new(name: &str, element_type: &str, size: usize) -> Self {
Self {
name: name.to_string(),
element_type: element_type.to_string(),
size,
access_mode: SyclAccessMode::ReadWrite,
}
}
pub fn to_declaration(&self) -> String {
format!(
"sycl::buffer<{}, 1> {}(sycl::range<1>({}))",
self.element_type, self.name, self.size
)
}
}
#[derive(Debug, Clone)]
pub struct SyclParallelFor {
pub kernel_name: String,
pub range: usize,
pub body: String,
}
impl SyclParallelFor {
pub fn new(kernel_name: &str, range: usize, body: &str) -> Self {
Self {
kernel_name: kernel_name.to_string(),
range,
body: body.to_string(),
}
}
pub fn to_code(&self, queue: &str) -> String {
format!(
"{}.submit([&](sycl::handler& cgh) {{\n\
cgh.parallel_for<class {}>(sycl::range<1>({}), \
[=](sycl::id<1> i) {{\n{}\n}});\n}});",
queue, self.kernel_name, self.range, self.body
)
}
}
#[derive(Debug, Clone)]
pub struct RustFFiBinding {
pub rust_name: String,
pub c_name: String,
pub return_type: String,
pub params: Vec<(String, String)>,
pub attributes: Vec<RustFFIAttribute>,
}
#[derive(Debug, Clone)]
pub enum RustFFIAttribute {
NoMangle,
ReprC,
ReprPacked,
ReprAlign(usize),
ExternC,
LinkName(String),
UnsafeFn,
}
impl RustFFiBinding {
pub fn new(rust_name: &str, c_name: &str, return_type: &str) -> Self {
Self {
rust_name: rust_name.to_string(),
c_name: c_name.to_string(),
return_type: return_type.to_string(),
params: Vec::new(),
attributes: vec![RustFFIAttribute::NoMangle, RustFFIAttribute::ExternC],
}
}
pub fn to_rust_extern_c(&self) -> String {
let mut out = String::new();
for attr in &self.attributes {
out.push_str(&match attr {
RustFFIAttribute::NoMangle => "#[no_mangle]\n".into(),
RustFFIAttribute::ExternC => "extern \"C\" ".into(),
RustFFIAttribute::ReprC => "#[repr(C)]\n".into(),
RustFFIAttribute::ReprPacked => "#[repr(packed)]\n".into(),
RustFFIAttribute::ReprAlign(n) => format!("#[repr(align({}))]\n", n),
RustFFIAttribute::LinkName(s) => format!("#[link_name = \"{}\"]\n", s),
RustFFIAttribute::UnsafeFn => "".into(),
});
}
let params_str: Vec<String> = self
.params
.iter()
.map(|(n, t)| format!("{}: {}", n, ctype_to_rust_type(t)))
.collect();
out.push_str(&format!(
"pub fn {}({}) -> {};",
self.c_name,
params_str.join(", "),
ctype_to_rust_type(&self.return_type)
));
out
}
pub fn to_rust_import(&self) -> String {
let params_str: Vec<String> = self
.params
.iter()
.map(|(n, t)| format!("{}: {}", n, ctype_to_rust_type(t)))
.collect();
format!(
"extern \"C\" {{\n pub fn {}({}) -> {};\n}}",
self.c_name,
params_str.join(", "),
ctype_to_rust_type(&self.return_type)
)
}
}
pub fn ctype_to_rust_type(ct: &str) -> &'static str {
match ct {
"void" => "()",
"char" => "std::os::raw::c_char",
"signed char" => "i8",
"unsigned char" => "u8",
"short" => "i16",
"unsigned short" => "u16",
"int" => "i32",
"unsigned int" => "u32",
"long" => "i64",
"unsigned long" => "u64",
"long long" => "i64",
"unsigned long long" => "u64",
"float" => "f32",
"double" => "f64",
"bool" | "_Bool" => "bool",
s if s.ends_with('*') => "*mut std::os::raw::c_void",
_ => "*mut std::os::raw::c_void",
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PythonFFIBackend {
Ctypes,
Cffi,
Cppyy,
Pybind11,
Cython,
}
impl PythonFFIBackend {
pub fn description(&self) -> &'static str {
match self {
Self::Ctypes => "ctypes — builtin Python FFI module",
Self::Cffi => "CFFI — C Foreign Function Interface for Python",
Self::Cppyy => "cppyy — automatic Python-C++ bindings",
Self::Pybind11 => "pybind11 — seamless C++11/Python binding",
Self::Cython => "Cython — C extensions for Python",
}
}
}
#[derive(Debug, Clone)]
pub struct PythonFFIBinding {
pub backend: PythonFFIBackend,
pub module_name: String,
pub functions: Vec<CExternFunction>,
}
impl PythonFFIBinding {
pub fn new(backend: PythonFFIBackend, module: &str) -> Self {
Self {
backend,
module_name: module.to_string(),
functions: Vec::new(),
}
}
pub fn to_ctypes_binding(&self) -> String {
let mut out = format!(
"import ctypes\n\n_lib = ctypes.CDLL('lib{}.so')\n\n",
self.module_name
);
for func in &self.functions {
let ret = ctype_to_python_ctype(&func.return_type);
let params: Vec<String> = func
.params
.iter()
.map(|(_, t)| ctype_to_python_ctype(t).to_string())
.collect();
out.push_str(&format!(
"_lib.{}.restype = {}\n_lib.{}.argtypes = [{}]\n\n",
func.name,
ret,
func.name,
params.join(", ")
));
}
out
}
pub fn to_cffi_binding(&self) -> String {
let mut out = format!("from cffi import FFI\n\nffi = FFI()\n\nffi.cdef(\"\"\"\n");
for func in &self.functions {
let params_str: Vec<String> = func
.params
.iter()
.map(|(n, t)| format!("{} {}", t, n))
.collect();
out.push_str(&format!(
" {} {}({});\n",
func.return_type,
func.name,
params_str.join(", ")
));
}
out.push_str(&format!(
"\"\"\")\n\n_lib = ffi.dlopen('lib{}.so')\n",
self.module_name
));
out
}
pub fn to_pybind11_binding(&self) -> String {
let mut out = format!("#include <pybind11/pybind11.h>\n\nnamespace py = pybind11;\n\n");
out.push_str(&format!("PYBIND11_MODULE({}, m) {{\n", self.module_name));
for func in &self.functions {
let params: Vec<&str> = func.params.iter().map(|(n, _)| n.as_str()).collect();
let py_params = if params.is_empty() {
String::new()
} else {
format!(", py::arg(\"{}\")", params.join("\"), py::arg(\""))
};
out.push_str(&format!(
" m.def(\"{}\", &{}{});\n",
func.name, func.name, py_params
));
}
out.push_str("}\n");
out
}
}
pub fn ctype_to_python_ctype(ct: &str) -> &'static str {
match ct {
"void" => "None",
"char" | "signed char" => "ctypes.c_char",
"unsigned char" => "ctypes.c_ubyte",
"short" => "ctypes.c_short",
"unsigned short" => "ctypes.c_ushort",
"int" => "ctypes.c_int",
"unsigned int" => "ctypes.c_uint",
"long" => "ctypes.c_long",
"unsigned long" => "ctypes.c_ulong",
"long long" => "ctypes.c_longlong",
"unsigned long long" => "ctypes.c_ulonglong",
"float" => "ctypes.c_float",
"double" => "ctypes.c_double",
"bool" | "_Bool" => "ctypes.c_bool",
s if s.ends_with('*') => "ctypes.c_void_p",
_ => "ctypes.c_void_p",
}
}
#[derive(Debug, Clone)]
pub struct InteropRegistry {
pub languages: Vec<InteropLanguage>,
pub functions: HashMap<String, CExternFunction>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InteropLanguage {
C,
CXX,
ObjC,
Cuda,
OpenCL,
Sycl,
Rust(usize),
Python(usize),
}
impl fmt::Display for InteropLanguage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::C => write!(f, "C"),
Self::CXX => write!(f, "C++"),
Self::ObjC => write!(f, "Objective-C"),
Self::Cuda => write!(f, "CUDA"),
Self::OpenCL => write!(f, "OpenCL"),
Self::Sycl => write!(f, "SYCL"),
Self::Rust(n) => write!(f, "Rust({} bindings)", n),
Self::Python(n) => write!(f, "Python({} bindings)", n),
}
}
}
impl InteropRegistry {
pub fn new() -> Self {
Self {
languages: Vec::new(),
functions: HashMap::new(),
}
}
pub fn register_function(&mut self, func: CExternFunction) {
self.functions.insert(func.name.clone(), func);
}
pub fn has_function(&self, name: &str) -> bool {
self.functions.contains_key(name)
}
pub fn function_count(&self) -> usize {
self.functions.len()
}
pub fn add_language(&mut self, lang: InteropLanguage) {
self.languages.push(lang);
}
pub fn generate_ffi_header(&self, language: InteropLanguage) -> String {
match language {
InteropLanguage::C | InteropLanguage::CXX => self
.functions
.values()
.map(|f| f.to_c_header())
.collect::<Vec<_>>()
.join("\n"),
InteropLanguage::Rust(_) => self
.functions
.values()
.map(|f| RustFFiBinding::new(&f.name, &f.name, &f.return_type).to_rust_import())
.collect::<Vec<_>>()
.join("\n"),
_ => "// unsupported language for header generation".to_string(),
}
}
}
impl Default for InteropRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cextern_function_to_extern_c() {
let mut func = CExternFunction::new("foo", "int");
func.add_param("x", "int");
func.add_param("y", "float");
let decl = func.to_extern_c();
assert!(decl.contains("extern \"C\""));
assert!(decl.contains("foo"));
assert!(decl.contains("int"));
}
#[test]
fn test_cextern_function_to_c_header() {
let mut func = CExternFunction::new("bar", "void");
func.add_param("ptr", "char*");
let header = func.to_c_header();
assert_eq!(header, "void bar(char* ptr);");
}
#[test]
fn test_cextern_function_variadic() {
let mut func = CExternFunction::new("printf", "int");
func.is_variadic = true;
func.add_param("fmt", "const char*");
let decl = func.to_extern_c();
assert!(decl.contains("..."));
}
#[test]
fn test_cextern_function_to_llvm_declare() {
let mut func = CExternFunction::new("add", "int");
func.add_param("a", "int");
func.add_param("b", "int");
let ir = func.to_llvm_declare();
assert!(ir.starts_with("declare"));
assert!(ir.contains("add"));
}
#[test]
fn test_ctype_to_llvm() {
assert_eq!(ctype_to_llvm("int"), "i32");
assert_eq!(ctype_to_llvm("double"), "double");
assert_eq!(ctype_to_llvm("void"), "void");
assert_eq!(ctype_to_llvm("unsigned long long"), "i64");
}
#[test]
fn test_objc_interface_to_declaration() {
let iface = ObjCInterface::new("MyClass");
let decl = iface.to_interface_declaration();
assert!(decl.contains("@interface MyClass"));
assert!(decl.contains("@end"));
}
#[test]
fn test_objc_interface_with_superclass() {
let mut iface = ObjCInterface::new("MyView");
iface.superclass = Some("UIView".into());
let decl = iface.to_interface_declaration();
assert!(decl.contains("UIView"));
}
#[test]
fn test_objc_message_send() {
let msg = ObjCMessageSend::new("obj", "doSomething:");
msg.arguments.push("42".into());
let code = msg.to_objc();
assert!(code.contains("[obj "));
assert!(code.contains("doSomething"));
}
#[test]
fn test_cuda_kernel_launch_syntax() {
let mut kernel = CudaKernel::new("myKernel", CudaFunctionKind::Global);
kernel.grid_dim = (16, 16, 1);
kernel.block_dim = (256, 1, 1);
let launch = kernel.to_launch_syntax();
assert!(launch.contains("<<<"));
assert!(launch.contains(">>>"));
assert!(launch.contains("dim3"));
}
#[test]
fn test_cuda_kernel_declaration() {
let kernel = CudaKernel::new("vecAdd", CudaFunctionKind::Global);
let decl = kernel.to_declaration();
assert!(decl.contains("__global__"));
assert!(decl.contains("vecAdd"));
}
#[test]
fn test_cuda_kind_display() {
assert_eq!(CudaFunctionKind::Global.to_string(), "__global__");
assert_eq!(
CudaFunctionKind::HostDevice.to_string(),
"__host__ __device__"
);
}
#[test]
fn test_cuda_memory_space_qualifier() {
assert_eq!(CudaMemorySpace::Shared.qualifier(), "__shared__");
assert_eq!(CudaMemorySpace::Constant.qualifier(), "__constant__");
assert_eq!(CudaMemorySpace::Managed.qualifier(), "__managed__");
}
#[test]
fn test_opencl_kernel_declaration() {
let mut kernel = OpenCLKernel::new("vec_add");
kernel
.params
.push(("a".into(), "float*".into(), OpenCLAddressSpace::Global));
kernel
.params
.push(("b".into(), "float*".into(), OpenCLAddressSpace::Global));
kernel.reqd_work_group_size = Some((256, 1, 1));
let decl = kernel.to_declaration();
assert!(decl.contains("__kernel"));
assert!(decl.contains("__global"));
assert!(decl.contains("vec_add"));
}
#[test]
fn test_opencl_address_space_qualifier() {
assert_eq!(OpenCLAddressSpace::Global.qualifier(), "__global");
assert_eq!(OpenCLAddressSpace::Local.qualifier(), "__local");
assert_eq!(OpenCLAddressSpace::Constant.qualifier(), "__constant");
}
#[test]
fn test_opencl_enqueue_call() {
let kernel = OpenCLKernel::new("k");
let call = kernel.to_enqueue_call("q", (1024, 1, 1), Some((256, 1, 1)));
assert!(call.contains("clEnqueueNDRangeKernel"));
assert!(call.contains("kernel_k"));
}
#[test]
fn test_sycl_queue_declaration() {
let mut q = SyclQueue::new("q");
q.device_selector = SyclDeviceSelector::GpuSelector;
let decl = q.to_declaration();
assert!(decl.contains("sycl::queue"));
assert!(decl.contains("gpu_selector"));
}
#[test]
fn test_sycl_buffer_declaration() {
let buf = SyclBuffer::new("buf", "float", 1024);
let decl = buf.to_declaration();
assert!(decl.contains("sycl::buffer<float, 1>"));
assert!(decl.contains("1024"));
}
#[test]
fn test_sycl_parallel_for() {
let pf = SyclParallelFor::new("MyKernel", 1024, "out[i] = in[i] * 2.0f;");
let code = pf.to_code("q");
assert!(code.contains("parallel_for"));
assert!(code.contains("MyKernel"));
assert!(code.contains("1024"));
}
#[test]
fn test_rust_ffi_binding_to_extern_c() {
let mut binding = RustFFiBinding::new("add_wrapper", "add", "int");
binding.params.push(("a".into(), "int".into()));
binding.params.push(("b".into(), "int".into()));
let rust_code = binding.to_rust_extern_c();
assert!(rust_code.contains("#[no_mangle]"));
assert!(rust_code.contains("extern \"C\""));
assert!(rust_code.contains("add"));
}
#[test]
fn test_rust_ffi_import() {
let mut binding = RustFFiBinding::new("", "free", "void");
binding.params.push(("ptr".into(), "void*".into()));
let import = binding.to_rust_import();
assert!(import.contains("extern \"C\""));
assert!(import.contains("free"));
}
#[test]
fn test_ctype_to_rust_type() {
assert_eq!(ctype_to_rust_type("int"), "i32");
assert_eq!(ctype_to_rust_type("double"), "f64");
assert_eq!(ctype_to_rust_type("void"), "()");
}
#[test]
fn test_python_ctypes_binding() {
let mut binding = PythonFFIBinding::new(PythonFFIBackend::Ctypes, "mylib");
let mut func = CExternFunction::new("add", "int");
func.add_param("a", "int");
func.add_param("b", "int");
binding.functions.push(func);
let code = binding.to_ctypes_binding();
assert!(code.contains("ctypes.CDLL"));
assert!(code.contains("ctypes.c_int"));
}
#[test]
fn test_python_cffi_binding() {
let mut binding = PythonFFIBinding::new(PythonFFIBackend::Cffi, "mylib");
let mut func = CExternFunction::new("foo", "double");
func.add_param("x", "int");
binding.functions.push(func);
let code = binding.to_cffi_binding();
assert!(code.contains("ffi.cdef"));
}
#[test]
fn test_python_pybind11_binding() {
let mut binding = PythonFFIBinding::new(PythonFFIBackend::Pybind11, "module");
let mut func = CExternFunction::new("compute", "int");
func.add_param("n", "int");
binding.functions.push(func);
let code = binding.to_pybind11_binding();
assert!(code.contains("PYBIND11_MODULE"));
assert!(code.contains("compute"));
}
#[test]
fn test_python_backend_descriptions() {
assert_eq!(
PythonFFIBackend::Ctypes.description(),
"ctypes — builtin Python FFI module"
);
assert_eq!(
PythonFFIBackend::Pybind11.description(),
"pybind11 — seamless C++11/Python binding"
);
}
#[test]
fn test_ctype_to_python_ctype() {
assert_eq!(ctype_to_python_ctype("int"), "ctypes.c_int");
assert_eq!(ctype_to_python_ctype("double"), "ctypes.c_double");
assert_eq!(ctype_to_python_ctype("void"), "None");
}
#[test]
fn test_interop_registry_register() {
let mut reg = InteropRegistry::new();
let func = CExternFunction::new("test", "int");
reg.register_function(func);
assert!(reg.has_function("test"));
assert_eq!(reg.function_count(), 1);
}
#[test]
fn test_interop_registry_generate_ffi_header() {
let mut reg = InteropRegistry::new();
let mut func = CExternFunction::new("add", "int");
func.add_param("a", "int");
reg.register_function(func);
let header = reg.generate_ffi_header(InteropLanguage::C);
assert!(header.contains("add"));
}
#[test]
fn test_interop_registry_generate_rust() {
let mut reg = InteropRegistry::new();
let mut func = CExternFunction::new("free", "void");
func.add_param("p", "void*");
reg.register_function(func);
let rust = reg.generate_ffi_header(InteropLanguage::Rust(1));
assert!(rust.contains("extern \"C\""));
}
#[test]
fn test_interop_language_display() {
assert_eq!(InteropLanguage::C.to_string(), "C");
assert_eq!(InteropLanguage::Cuda.to_string(), "CUDA");
assert_eq!(InteropLanguage::Rust(5).to_string(), "Rust(5 bindings)");
}
#[test]
fn test_cxx_extern_function() {
let mut f = CXXExternFunction::new("func", "int");
f.exception_spec = ExceptionSpec::Noexcept;
let decl = f.extern_c_declaration();
assert!(decl.contains("extern \"C\""));
}
}