Skip to main content

gaia_assembler/adapters/
mod.rs

1//! Unified Adapter Interface Definitions
2//!
3//! This module defines the unified interface for import and export adapters,
4//! as well as related configuration and management structures.
5//! These interfaces aim to abstract differences between platforms and provide a consistent API.
6
7use crate::{config::GaiaSettings, instruction::GaiaInstruction, program::GaiaModule};
8use gaia_types::{
9    helpers::{AbiCompatible, ApiCompatible, Architecture, CompilationTarget},
10    GaiaError, Result,
11};
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14
15/// Adapter configuration information.
16///
17/// Contains configuration parameters required for the adapter's operation.
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct AdapterConfig {
20    /// Adapter name.
21    pub name: String,
22    /// Compilation target.
23    pub compilation_target: CompilationTarget,
24    /// Configuration parameters.
25    pub parameters: HashMap<String, String>,
26    /// Whether the adapter is enabled.
27    pub enabled: bool,
28}
29
30/// Adapter metadata.
31///
32/// Describes basic information and capabilities of an adapter.
33#[derive(Debug, Clone)]
34pub struct AdapterMetadata {
35    /// Adapter name.
36    pub name: String,
37    /// Adapter version.
38    pub version: String,
39    /// Supported compilation target.
40    pub compilation_target: CompilationTarget,
41    /// Adapter description.
42    pub description: String,
43    /// Supported instruction sets.
44    pub supported_instructions: Vec<String>,
45}
46
47/// Function mapper.
48#[derive(Debug)]
49pub struct FunctionMapper {
50    /// Function mapping table (platform -> source function -> target function).
51    mappings: HashMap<CompilationTarget, HashMap<String, String>>,
52}
53
54impl FunctionMapper {
55    /// Create a new function mapper with default mappings.
56    pub fn new() -> Self {
57        // Uniform initialization using default GaiaSettings to avoid hardcoded repetition.
58        // Default mappings include universal functions like __builtin_print / malloc / free.
59        Self::from_settings(&GaiaSettings::default())
60    }
61
62    /// Create a function mapper from a configuration.
63    pub fn from_config(config: &GaiaSettings) -> Result<Self> {
64        Ok(Self::from_settings(config))
65    }
66
67    /// Generate unified function mappings based on GaiaSettings (overrides defaults).
68    fn from_settings(settings: &GaiaSettings) -> Self {
69        let mut mapper = Self { mappings: HashMap::new() };
70
71        // Predefined platform targets (uniform keys: IL/JVM/PE/WASI).
72        let il_target = CompilationTarget {
73            build: Architecture::CLR,
74            host: AbiCompatible::MicrosoftIntermediateLanguage,
75            target: ApiCompatible::ClrRuntime(4),
76        };
77        let jvm_target = CompilationTarget {
78            build: Architecture::JVM,
79            host: AbiCompatible::JavaAssembly,
80            target: ApiCompatible::JvmRuntime(8),
81        };
82        let pe_target =
83            CompilationTarget { build: Architecture::X86_64, host: AbiCompatible::PE, target: ApiCompatible::MicrosoftVisualC };
84        let wasi_target = CompilationTarget {
85            build: Architecture::WASM32,
86            host: AbiCompatible::WebAssemblyTextFormat,
87            target: ApiCompatible::WASI,
88        };
89
90        let mut platform_index: HashMap<String, CompilationTarget> = HashMap::new();
91        platform_index.insert("IL".to_string(), il_target.clone());
92        platform_index.insert("JVM".to_string(), jvm_target.clone());
93        platform_index.insert("PE".to_string(), pe_target.clone());
94        platform_index.insert("WASI".to_string(), wasi_target.clone());
95
96        // 1) Baseline: Provide reasonable default aliases to prevent issues if settings are missing.
97        // IL default: WriteLine with signature, compatible with current MsilWriter call syntax.
98        mapper.add_mapping(&il_target, "console.log", "void [mscorlib]System.Console::WriteLine(string)");
99        mapper.add_mapping(&il_target, "console.write", "void [mscorlib]System.Console::WriteLine(string)");
100        mapper.add_mapping(&il_target, "conosole.read", "string [mscorlib]System.Console::ReadLine()");
101        mapper.add_mapping(&il_target, "malloc", "System.Runtime.InteropServices.Marshal.AllocHGlobal");
102        mapper.add_mapping(&il_target, "free", "System.Runtime.InteropServices.Marshal.FreeHGlobal");
103        mapper.add_mapping(&il_target, "print", "void [mscorlib]System.Console::WriteLine(string)");
104        mapper.add_mapping(&il_target, "println", "void [mscorlib]System.Console::WriteLine(string)");
105
106        // JVM defaults
107        mapper.add_mapping(&jvm_target, "console.log", "java.lang.System.out.println");
108        mapper.add_mapping(&jvm_target, "console.write", "java.lang.System.out.println");
109        mapper.add_mapping(&jvm_target, "console.read", "java.util.Scanner.nextLine");
110        mapper.add_mapping(&jvm_target, "malloc", "java.nio.ByteBuffer.allocateDirect");
111        mapper.add_mapping(&jvm_target, "free", "System.gc");
112        mapper.add_mapping(&jvm_target, "print", "java.lang.System.out.println");
113        mapper.add_mapping(&jvm_target, "println", "java.lang.System.out.println");
114
115        // PE defaults
116        mapper.add_mapping(&pe_target, "console.log", "puts");
117        mapper.add_mapping(&pe_target, "console.write", "printf");
118        mapper.add_mapping(&pe_target, "console.read", "gets_s");
119        mapper.add_mapping(&pe_target, "malloc", "HeapAlloc");
120        mapper.add_mapping(&pe_target, "free", "HeapFree");
121        mapper.add_mapping(&pe_target, "print", "puts");
122        mapper.add_mapping(&pe_target, "println", "puts");
123
124        // WASI defaults
125        mapper.add_mapping(&wasi_target, "console.log", "wasi_println");
126        mapper.add_mapping(&wasi_target, "console.write", "wasi_print");
127        mapper.add_mapping(&wasi_target, "console.read", "wasi_read");
128        mapper.add_mapping(&wasi_target, "malloc", "malloc");
129        mapper.add_mapping(&wasi_target, "free", "free");
130        mapper.add_mapping(&wasi_target, "print", "wasi_println");
131        mapper.add_mapping(&wasi_target, "println", "wasi_println");
132
133        // 2) Override: Use settings.function_mappings to override/extend default mappings
134        for fm in &settings.function_mappings {
135            for (platform_name, target_func) in &fm.platform_mappings {
136                let key = platform_name.to_ascii_uppercase();
137                if let Some(platform_target) = platform_index.get(&key) {
138                    // Directly map common name
139                    mapper.add_mapping(platform_target, &fm.common_name, target_func);
140
141                    // Provide linkage for common aliases (reducing front-end repetition)
142                    if fm.common_name == "__builtin_print" {
143                        let is_il = matches!(platform_target.host, AbiCompatible::MicrosoftIntermediateLanguage);
144                        // The IL platform retains the default print mapping with a signature to avoid generating incomplete MSIL call operands.
145                        if !is_il {
146                            mapper.add_mapping(platform_target, "print", target_func);
147                        }
148                        mapper.add_mapping(platform_target, "console.log", target_func);
149                        mapper.add_mapping(platform_target, "console.write", target_func);
150                    }
151                }
152            }
153        }
154
155        mapper
156    }
157
158    /// Add function mapping
159    pub fn add_mapping(&mut self, target: &CompilationTarget, source_func: &str, target_func: &str) {
160        self.mappings
161            .entry(target.clone())
162            .or_insert_with(HashMap::new)
163            .insert(source_func.to_string(), target_func.to_string());
164    }
165
166    /// Map function name
167    pub fn map_function(&self, target: &CompilationTarget, function_name: &str) -> Option<&str> {
168        self.mappings.get(target).and_then(|platform_mappings| platform_mappings.get(function_name)).map(|s| s.as_str())
169    }
170}
171
172impl Default for FunctionMapper {
173    fn default() -> Self {
174        Self::new()
175    }
176}
177
178/// Unified Export Adapter Interface
179///
180/// Defines a standard interface for exporting Gaia instructions and programs to platform-specific formats.
181pub trait ExportAdapter: Send + Sync {
182    /// Get adapter metadata
183    fn metadata(&self) -> &AdapterMetadata;
184
185    /// Configure adapter
186    ///
187    /// # Parameters
188    /// * `config` - Adapter configuration
189    ///
190    /// # Return Value
191    /// Returns Ok(()) on success, or an error message on failure.
192    fn configure(&mut self, config: AdapterConfig) -> Result<()>;
193
194    /// Export a single instruction
195    ///
196    /// # Parameters
197    /// * `instruction` - Gaia instruction to export
198    ///
199    /// # Return Value
200    /// Returns platform-specific instruction data on success, or an error message on failure.
201    fn export_instruction(&self, instruction: &GaiaInstruction) -> Result<Vec<u8>>;
202
203    /// Export the complete program
204    ///
205    /// # Parameters
206    /// * `program` - Gaia program to be exported
207    ///
208    /// # Return Value
209    /// Returns platform-specific program data on success, or an error message on failure.
210    fn export_program(&self, program: &GaiaModule) -> Result<Vec<u8>>;
211
212    /// Verify if the instruction is supported
213    ///
214    /// # Parameters
215    /// * `instruction` - Instruction to verify
216    ///
217    /// # Return Value
218    /// Returns true if supported, false otherwise.
219    fn supports_instruction(&self, instruction: &GaiaInstruction) -> bool;
220
221    /// Get the output file extension
222    ///
223    /// # Return Value
224    /// Platform-specific file extension
225    fn file_extension(&self) -> &str;
226
227    /// Clean up resources
228    ///
229    /// Called when the adapter is no longer in use to clean up related resources
230    fn cleanup(&mut self) -> Result<()> {
231        Ok(())
232    }
233}
234
235/// Unified Import Adapter Interface
236///
237/// Defines a standard interface for importing from platform-specific formats to Gaia instructions and programs.
238pub trait ImportAdapter: Send + Sync {
239    /// Get adapter metadata
240    fn metadata(&self) -> &AdapterMetadata;
241
242    /// Configure adapter
243    ///
244    /// # Parameters
245    /// * `config` - Adapter configuration
246    ///
247    /// # Return Value
248    /// Returns Ok(()) on success, or an error message on failure.
249    fn configure(&mut self, config: AdapterConfig) -> Result<()>;
250
251    /// Import a single instruction
252    ///
253    /// # Parameters
254    /// * `data` - Platform-specific instruction data
255    ///
256    /// # Return Value
257    /// Returns Gaia instruction on success, or an error message on failure.
258    fn import_instruction(&self, data: &[u8]) -> Result<GaiaInstruction>;
259
260    /// Import program
261    ///
262    /// # Parameters
263    /// * `data` - Platform-specific program data
264    ///
265    /// # Return Value
266    /// Returns the converted Gaia program on success, or an error message on failure.
267    fn import_program(&self, data: &[u8]) -> Result<GaiaModule>;
268
269    /// Validate data format
270    ///
271    /// # Parameters
272    /// * `data` - Data to validate
273    ///
274    /// # Return Value
275    /// Returns true if the format is correct, false otherwise.
276    fn validate_format(&self, data: &[u8]) -> bool;
277
278    /// Get supported file extensions
279    ///
280    /// # Return Value
281    /// List of supported file extensions
282    fn supported_extensions(&self) -> Vec<&str>;
283
284    /// Clean up resources
285    ///
286    /// Called when the adapter is no longer in use to clean up related resources
287    fn cleanup(&mut self) -> Result<()> {
288        Ok(())
289    }
290}
291
292/// Adapter Manager
293pub struct AdapterManager {
294    /// Export adapter registry
295    export_adapters: HashMap<CompilationTarget, Box<dyn ExportAdapter>>,
296    /// Import adapter registry
297    import_adapters: HashMap<CompilationTarget, Box<dyn ImportAdapter>>,
298}
299
300impl AdapterManager {
301    /// Create a new adapter manager
302    pub fn new() -> Self {
303        Self { export_adapters: HashMap::new(), import_adapters: HashMap::new() }
304    }
305
306    /// Register export adapter
307    ///
308    /// # Parameters
309    /// * `target` - Compilation target
310    /// * `adapter` - Export adapter to register
311    ///
312    /// # Return Value
313    /// Returns Ok(()) on success, or an error message on failure.
314    pub fn register_export_adapter(&mut self, target: CompilationTarget, adapter: Box<dyn ExportAdapter>) -> Result<()> {
315        if self.export_adapters.contains_key(&target) {
316            return Err(GaiaError::adapter_error(&format!("{:?}", target), "Export adapter already exists", None));
317        }
318        self.export_adapters.insert(target, adapter);
319        Ok(())
320    }
321
322    /// Register import adapter
323    ///
324    /// # Parameters
325    /// * `target` - Compilation target
326    /// * `adapter` - Import adapter to register
327    ///
328    /// # Return Value
329    /// Returns Ok(()) on success, or an error message on failure.
330    pub fn register_import_adapter(&mut self, target: CompilationTarget, adapter: Box<dyn ImportAdapter>) -> Result<()> {
331        if self.import_adapters.contains_key(&target) {
332            return Err(GaiaError::adapter_error(&format!("{:?}", target), "Import adapter already exists", None));
333        }
334        self.import_adapters.insert(target, adapter);
335        Ok(())
336    }
337
338    /// Get export adapter
339    ///
340    /// # Parameters
341    /// * `target` - Compilation target
342    ///
343    /// # Return Value
344    /// Returns adapter reference if found, or an error otherwise.
345    pub fn get_export_adapter(&self, target: &CompilationTarget) -> Result<&dyn ExportAdapter> {
346        self.export_adapters
347            .get(target)
348            .map(|adapter| adapter.as_ref())
349            .ok_or_else(|| GaiaError::adapter_error(&format!("{:?}", target), "Export adapter not found", None))
350    }
351
352    /// Get mutable export adapter
353    ///
354    /// # Parameters
355    /// * `target` - Compilation target
356    ///
357    /// # Return Value
358    /// Returns mutable adapter reference if found, or an error otherwise.
359    pub fn get_export_adapter_mut(&mut self, target: &CompilationTarget) -> Result<&mut (dyn ExportAdapter + '_)> {
360        match self.export_adapters.get_mut(target) {
361            Some(adapter) => Ok(adapter.as_mut()),
362            None => Err(GaiaError::adapter_error(&format!("{:?}", target), "Export adapter not found", None)),
363        }
364    }
365
366    /// Get import adapter
367    ///
368    /// # Parameters
369    /// * `target` - Compilation target
370    ///
371    /// # Return Value
372    /// Returns adapter reference if found, or an error otherwise.
373    pub fn get_import_adapter(&self, target: &CompilationTarget) -> Result<&dyn ImportAdapter> {
374        self.import_adapters
375            .get(target)
376            .map(|adapter| adapter.as_ref())
377            .ok_or_else(|| GaiaError::adapter_error(&format!("{:?}", target), "Import adapter not found", None))
378    }
379
380    /// Get mutable import adapter
381    ///
382    /// # Parameters
383    /// * `target` - Compilation target
384    ///
385    /// # Return Value
386    /// Returns mutable adapter reference if found, or an error otherwise.
387    pub fn get_import_adapter_mut(&mut self, target: &CompilationTarget) -> Result<&mut (dyn ImportAdapter + '_)> {
388        match self.import_adapters.get_mut(target) {
389            Some(adapter) => Ok(adapter.as_mut()),
390            None => Err(GaiaError::adapter_error(&format!("{:?}", target), "Import adapter not found", None)),
391        }
392    }
393
394    /// List all supported compilation targets
395    ///
396    /// # Return Value
397    /// List of compilation targets
398    pub fn list_supported_targets(&self) -> Vec<CompilationTarget> {
399        let mut targets = Vec::new();
400        targets.extend(self.export_adapters.keys().cloned());
401        targets.extend(self.import_adapters.keys().cloned());
402        targets.sort_by_key(|t| format!("{:?}", t));
403        targets.dedup();
404        targets
405    }
406
407    /// Clean up all adapter resources
408    ///
409    /// # Return Value
410    /// Returns Ok(()) on success, or an error message on failure.
411    pub fn cleanup_all(&mut self) -> Result<()> {
412        for (target, adapter) in &mut self.export_adapters {
413            if let Err(e) = adapter.cleanup() {
414                return Err(GaiaError::adapter_error(
415                    &format!("{:?}", target),
416                    "Failed to clean up export adapter",
417                    Some(Box::new(e)),
418                ));
419            }
420        }
421
422        for (target, adapter) in &mut self.import_adapters {
423            if let Err(e) = adapter.cleanup() {
424                return Err(GaiaError::adapter_error(
425                    &format!("{:?}", target),
426                    "Failed to clean up import adapter",
427                    Some(Box::new(e)),
428                ));
429            }
430        }
431
432        Ok(())
433    }
434}
435
436impl Default for AdapterManager {
437    fn default() -> Self {
438        Self::new()
439    }
440}