use crate::{config::GaiaSettings, instruction::GaiaInstruction, program::GaiaModule};
use gaia_types::{
helpers::{AbiCompatible, ApiCompatible, Architecture, CompilationTarget},
GaiaError, Result,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdapterConfig {
pub name: String,
pub compilation_target: CompilationTarget,
pub parameters: HashMap<String, String>,
pub enabled: bool,
}
#[derive(Debug, Clone)]
pub struct AdapterMetadata {
pub name: String,
pub version: String,
pub compilation_target: CompilationTarget,
pub description: String,
pub supported_instructions: Vec<String>,
}
#[derive(Debug)]
pub struct FunctionMapper {
mappings: HashMap<CompilationTarget, HashMap<String, String>>,
}
impl FunctionMapper {
pub fn new() -> Self {
Self::from_settings(&GaiaSettings::default())
}
pub fn from_config(config: &GaiaSettings) -> Result<Self> {
Ok(Self::from_settings(config))
}
fn from_settings(settings: &GaiaSettings) -> Self {
let mut mapper = Self { mappings: HashMap::new() };
let il_target = CompilationTarget {
build: Architecture::CLR,
host: AbiCompatible::MicrosoftIntermediateLanguage,
target: ApiCompatible::ClrRuntime(4),
};
let jvm_target = CompilationTarget {
build: Architecture::JVM,
host: AbiCompatible::JavaAssembly,
target: ApiCompatible::JvmRuntime(8),
};
let pe_target =
CompilationTarget { build: Architecture::X86_64, host: AbiCompatible::PE, target: ApiCompatible::MicrosoftVisualC };
let wasi_target = CompilationTarget {
build: Architecture::WASM32,
host: AbiCompatible::WebAssemblyTextFormat,
target: ApiCompatible::WASI,
};
let mut platform_index: HashMap<String, CompilationTarget> = HashMap::new();
platform_index.insert("IL".to_string(), il_target.clone());
platform_index.insert("JVM".to_string(), jvm_target.clone());
platform_index.insert("PE".to_string(), pe_target.clone());
platform_index.insert("WASI".to_string(), wasi_target.clone());
mapper.add_mapping(&il_target, "console.log", "void [mscorlib]System.Console::WriteLine(string)");
mapper.add_mapping(&il_target, "console.write", "void [mscorlib]System.Console::WriteLine(string)");
mapper.add_mapping(&il_target, "conosole.read", "string [mscorlib]System.Console::ReadLine()");
mapper.add_mapping(&il_target, "malloc", "System.Runtime.InteropServices.Marshal.AllocHGlobal");
mapper.add_mapping(&il_target, "free", "System.Runtime.InteropServices.Marshal.FreeHGlobal");
mapper.add_mapping(&il_target, "print", "void [mscorlib]System.Console::WriteLine(string)");
mapper.add_mapping(&il_target, "println", "void [mscorlib]System.Console::WriteLine(string)");
mapper.add_mapping(&jvm_target, "console.log", "java.lang.System.out.println");
mapper.add_mapping(&jvm_target, "console.write", "java.lang.System.out.println");
mapper.add_mapping(&jvm_target, "console.read", "java.util.Scanner.nextLine");
mapper.add_mapping(&jvm_target, "malloc", "java.nio.ByteBuffer.allocateDirect");
mapper.add_mapping(&jvm_target, "free", "System.gc");
mapper.add_mapping(&jvm_target, "print", "java.lang.System.out.println");
mapper.add_mapping(&jvm_target, "println", "java.lang.System.out.println");
mapper.add_mapping(&pe_target, "console.log", "puts");
mapper.add_mapping(&pe_target, "console.write", "printf");
mapper.add_mapping(&pe_target, "console.read", "gets_s");
mapper.add_mapping(&pe_target, "malloc", "HeapAlloc");
mapper.add_mapping(&pe_target, "free", "HeapFree");
mapper.add_mapping(&pe_target, "print", "puts");
mapper.add_mapping(&pe_target, "println", "puts");
mapper.add_mapping(&wasi_target, "console.log", "wasi_println");
mapper.add_mapping(&wasi_target, "console.write", "wasi_print");
mapper.add_mapping(&wasi_target, "console.read", "wasi_read");
mapper.add_mapping(&wasi_target, "malloc", "malloc");
mapper.add_mapping(&wasi_target, "free", "free");
mapper.add_mapping(&wasi_target, "print", "wasi_println");
mapper.add_mapping(&wasi_target, "println", "wasi_println");
for fm in &settings.function_mappings {
for (platform_name, target_func) in &fm.platform_mappings {
let key = platform_name.to_ascii_uppercase();
if let Some(platform_target) = platform_index.get(&key) {
mapper.add_mapping(platform_target, &fm.common_name, target_func);
if fm.common_name == "__builtin_print" {
let is_il = matches!(platform_target.host, AbiCompatible::MicrosoftIntermediateLanguage);
if !is_il {
mapper.add_mapping(platform_target, "print", target_func);
}
mapper.add_mapping(platform_target, "console.log", target_func);
mapper.add_mapping(platform_target, "console.write", target_func);
}
}
}
}
mapper
}
pub fn add_mapping(&mut self, target: &CompilationTarget, source_func: &str, target_func: &str) {
self.mappings
.entry(target.clone())
.or_insert_with(HashMap::new)
.insert(source_func.to_string(), target_func.to_string());
}
pub fn map_function(&self, target: &CompilationTarget, function_name: &str) -> Option<&str> {
self.mappings.get(target).and_then(|platform_mappings| platform_mappings.get(function_name)).map(|s| s.as_str())
}
}
impl Default for FunctionMapper {
fn default() -> Self {
Self::new()
}
}
pub trait ExportAdapter: Send + Sync {
fn metadata(&self) -> &AdapterMetadata;
fn configure(&mut self, config: AdapterConfig) -> Result<()>;
fn export_instruction(&self, instruction: &GaiaInstruction) -> Result<Vec<u8>>;
fn export_program(&self, program: &GaiaModule) -> Result<Vec<u8>>;
fn supports_instruction(&self, instruction: &GaiaInstruction) -> bool;
fn file_extension(&self) -> &str;
fn cleanup(&mut self) -> Result<()> {
Ok(())
}
}
pub trait ImportAdapter: Send + Sync {
fn metadata(&self) -> &AdapterMetadata;
fn configure(&mut self, config: AdapterConfig) -> Result<()>;
fn import_instruction(&self, data: &[u8]) -> Result<GaiaInstruction>;
fn import_program(&self, data: &[u8]) -> Result<GaiaModule>;
fn validate_format(&self, data: &[u8]) -> bool;
fn supported_extensions(&self) -> Vec<&str>;
fn cleanup(&mut self) -> Result<()> {
Ok(())
}
}
pub struct AdapterManager {
export_adapters: HashMap<CompilationTarget, Box<dyn ExportAdapter>>,
import_adapters: HashMap<CompilationTarget, Box<dyn ImportAdapter>>,
}
impl AdapterManager {
pub fn new() -> Self {
Self { export_adapters: HashMap::new(), import_adapters: HashMap::new() }
}
pub fn register_export_adapter(&mut self, target: CompilationTarget, adapter: Box<dyn ExportAdapter>) -> Result<()> {
if self.export_adapters.contains_key(&target) {
return Err(GaiaError::adapter_error(&format!("{:?}", target), "Export adapter already exists", None));
}
self.export_adapters.insert(target, adapter);
Ok(())
}
pub fn register_import_adapter(&mut self, target: CompilationTarget, adapter: Box<dyn ImportAdapter>) -> Result<()> {
if self.import_adapters.contains_key(&target) {
return Err(GaiaError::adapter_error(&format!("{:?}", target), "Import adapter already exists", None));
}
self.import_adapters.insert(target, adapter);
Ok(())
}
pub fn get_export_adapter(&self, target: &CompilationTarget) -> Result<&dyn ExportAdapter> {
self.export_adapters
.get(target)
.map(|adapter| adapter.as_ref())
.ok_or_else(|| GaiaError::adapter_error(&format!("{:?}", target), "Export adapter not found", None))
}
pub fn get_export_adapter_mut(&mut self, target: &CompilationTarget) -> Result<&mut (dyn ExportAdapter + '_)> {
match self.export_adapters.get_mut(target) {
Some(adapter) => Ok(adapter.as_mut()),
None => Err(GaiaError::adapter_error(&format!("{:?}", target), "Export adapter not found", None)),
}
}
pub fn get_import_adapter(&self, target: &CompilationTarget) -> Result<&dyn ImportAdapter> {
self.import_adapters
.get(target)
.map(|adapter| adapter.as_ref())
.ok_or_else(|| GaiaError::adapter_error(&format!("{:?}", target), "Import adapter not found", None))
}
pub fn get_import_adapter_mut(&mut self, target: &CompilationTarget) -> Result<&mut (dyn ImportAdapter + '_)> {
match self.import_adapters.get_mut(target) {
Some(adapter) => Ok(adapter.as_mut()),
None => Err(GaiaError::adapter_error(&format!("{:?}", target), "Import adapter not found", None)),
}
}
pub fn list_supported_targets(&self) -> Vec<CompilationTarget> {
let mut targets = Vec::new();
targets.extend(self.export_adapters.keys().cloned());
targets.extend(self.import_adapters.keys().cloned());
targets.sort_by_key(|t| format!("{:?}", t));
targets.dedup();
targets
}
pub fn cleanup_all(&mut self) -> Result<()> {
for (target, adapter) in &mut self.export_adapters {
if let Err(e) = adapter.cleanup() {
return Err(GaiaError::adapter_error(
&format!("{:?}", target),
"Failed to clean up export adapter",
Some(Box::new(e)),
));
}
}
for (target, adapter) in &mut self.import_adapters {
if let Err(e) = adapter.cleanup() {
return Err(GaiaError::adapter_error(
&format!("{:?}", target),
"Failed to clean up import adapter",
Some(Box::new(e)),
));
}
}
Ok(())
}
}
impl Default for AdapterManager {
fn default() -> Self {
Self::new()
}
}