Skip to main content

gaia_assembler/config/
mod.rs

1//! Configuration Management Module
2//!
3//! This module is responsible for loading and managing the Gaia assembler's configuration,
4//! including platform mappings and adapter configurations.
5//! It supports dynamic loading from TOML configuration files.
6
7use gaia_types::{
8    helpers::{AbiCompatible, ApiCompatible, Architecture, CompilationTarget},
9    GaiaError, Result,
10};
11use serde::{Deserialize, Serialize};
12use std::{collections::HashMap, fs, path::Path};
13
14/// Function mapping configuration.
15///
16/// Defines the mapping from generic function names to platform-specific function names.
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct FunctionMapping {
19    /// Generic function name.
20    pub common_name: String,
21    /// Platform-specific mappings.
22    pub platform_mappings: HashMap<String, String>,
23    /// Function description.
24    pub description: Option<String>,
25}
26
27/// Platform configuration.
28///
29/// Contains configuration information for a specific platform.
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct PlatformConfig {
32    /// Compilation target.
33    pub target: CompilationTarget,
34    /// Platform description.
35    pub description: Option<String>,
36    /// Supported architectures.
37    pub supported_architectures: Vec<String>,
38    /// Default file extension.
39    pub default_extension: String,
40    /// Platform-specific parameters.
41    pub parameters: HashMap<String, String>,
42}
43
44/// Adapter configuration.
45///
46/// Contains configuration information for an adapter.
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct AdapterConfigEntry {
49    /// Adapter name.
50    pub name: String,
51    /// Adapter type (export/import).
52    pub adapter_type: String,
53    /// Compilation target.
54    pub compilation_target: CompilationTarget,
55    /// Whether the adapter is enabled.
56    pub enabled: bool,
57    /// Adapter parameters.
58    pub parameters: HashMap<String, String>,
59}
60
61/// Global configuration.
62///
63/// Contains global setting parameters.
64#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct GlobalConfig {
66    /// Default output directory.
67    pub default_output_dir: String,
68    /// Whether debug mode is enabled.
69    pub debug_mode: bool,
70    /// Global parameters.
71    pub parameters: HashMap<String, String>,
72}
73
74impl Default for GlobalConfig {
75    fn default() -> Self {
76        Self { default_output_dir: "./target".to_string(), debug_mode: false, parameters: HashMap::new() }
77    }
78}
79
80/// Gaia configuration containing both static settings and compilation target.
81#[derive(Debug, Clone)]
82pub struct GaiaConfig {
83    /// Static settings loaded from configuration files.
84    pub setting: GaiaSettings,
85    /// The compilation target for this configuration.
86    pub target: CompilationTarget,
87}
88
89impl Default for GaiaConfig {
90    fn default() -> Self {
91        Self {
92            setting: GaiaSettings::default(),
93            target: CompilationTarget {
94                build: Architecture::Unknown,
95                host: AbiCompatible::Unknown,
96                target: ApiCompatible::Unknown,
97            },
98        }
99    }
100}
101
102/// Main configuration for the Gaia assembler
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct GaiaSettings {
105    /// Configuration version
106    pub version: String,
107    /// Global settings
108    pub global: GlobalConfig,
109    /// Platform configuration mappings
110    #[serde(with = "target_map_serde")]
111    pub platforms: HashMap<CompilationTarget, PlatformConfig>,
112    /// Function mapping list
113    pub function_mappings: Vec<FunctionMapping>,
114    /// Adapter configuration list
115    pub adapters: Vec<AdapterConfigEntry>,
116}
117
118mod target_map_serde {
119    use super::*;
120    use serde::{Deserializer, Serializer};
121    use std::str::FromStr;
122
123    pub fn serialize<S>(map: &HashMap<CompilationTarget, PlatformConfig>, serializer: S) -> std::result::Result<S::Ok, S::Error>
124    where
125        S: Serializer,
126    {
127        let string_map: HashMap<String, PlatformConfig> = map.iter().map(|(k, v)| (k.to_string(), v.clone())).collect();
128        string_map.serialize(serializer)
129    }
130
131    pub fn deserialize<'de, D>(deserializer: D) -> std::result::Result<HashMap<CompilationTarget, PlatformConfig>, D::Error>
132    where
133        D: Deserializer<'de>,
134    {
135        let string_map: HashMap<String, PlatformConfig> = HashMap::deserialize(deserializer)?;
136        let mut map = HashMap::new();
137        for (k, v) in string_map {
138            // NOTE: This assumes CompilationTarget::from_str is implemented or we have a way to parse it.
139            // CompilationTarget has Display, but does it have FromStr?
140            // Let's check gaia_types.
141            let target = parse_target(&k).map_err(serde::de::Error::custom)?;
142            map.insert(target, v);
143        }
144        Ok(map)
145    }
146
147    fn parse_target(s: &str) -> std::result::Result<CompilationTarget, String> {
148        let parts: Vec<&str> = s.split('-').collect();
149        if parts.len() != 3 {
150            return Err(format!("Invalid compilation target string: {}", s));
151        }
152
153        let build = Architecture::from_str(parts[0])?;
154        let host = AbiCompatible::from_str(parts[1])?;
155        let target = ApiCompatible::from_str(parts[2])?;
156
157        Ok(CompilationTarget { build, host, target })
158    }
159}
160
161impl Default for GaiaSettings {
162    fn default() -> Self {
163        Self {
164            version: "1.0.0".to_string(),
165            global: GlobalConfig::default(),
166            platforms: {
167                let mut platforms = HashMap::new();
168                let x64_target = CompilationTarget {
169                    build: Architecture::X86_64,
170                    host: AbiCompatible::PE,
171                    target: ApiCompatible::MicrosoftVisualC,
172                };
173                platforms.insert(
174                    x64_target.clone(),
175                    PlatformConfig {
176                        target: x64_target,
177                        description: Some("Windows x64 Native".to_string()),
178                        supported_architectures: vec!["x86_64".to_string()],
179                        default_extension: ".exe".to_string(),
180                        parameters: HashMap::new(),
181                    },
182                );
183
184                let clr_target = CompilationTarget {
185                    build: Architecture::CLR,
186                    host: AbiCompatible::PE,
187                    target: ApiCompatible::ClrRuntime(4),
188                };
189                platforms.insert(
190                    clr_target.clone(),
191                    PlatformConfig {
192                        target: clr_target,
193                        description: Some(".NET CLR v4.0".to_string()),
194                        supported_architectures: vec!["msil".to_string()],
195                        default_extension: ".exe".to_string(),
196                        parameters: HashMap::new(),
197                    },
198                );
199                platforms
200            },
201            function_mappings: vec![
202                FunctionMapping {
203                    common_name: "__builtin_print".to_string(),
204                    platform_mappings: [
205                        ("PE".to_string(), "printf".to_string()),
206                        ("IL".to_string(), "System.Console.WriteLine".to_string()),
207                        ("JVM".to_string(), "java.lang.System.out.println".to_string()),
208                        ("WASI".to_string(), "fd_write".to_string()),
209                    ]
210                    .into_iter()
211                    .collect(),
212                    description: Some("Standard output function".to_string()),
213                },
214                FunctionMapping {
215                    common_name: "malloc".to_string(),
216                    platform_mappings: [
217                        ("PE".to_string(), "malloc".to_string()),
218                        ("IL".to_string(), "System.Runtime.InteropServices.Marshal.AllocHGlobal".to_string()),
219                        ("JVM".to_string(), "java.nio.ByteBuffer.allocate".to_string()),
220                        ("WASI".to_string(), "memory.grow".to_string()),
221                    ]
222                    .into_iter()
223                    .collect(),
224                    description: Some("Memory allocation function".to_string()),
225                },
226                FunctionMapping {
227                    common_name: "free".to_string(),
228                    platform_mappings: [
229                        ("PE".to_string(), "free".to_string()),
230                        ("IL".to_string(), "System.Runtime.InteropServices.Marshal.FreeHGlobal".to_string()),
231                        ("JVM".to_string(), "System.gc".to_string()),
232                        ("WASI".to_string(), "memory.shrink".to_string()),
233                    ]
234                    .into_iter()
235                    .collect(),
236                    description: Some("Memory deallocation function".to_string()),
237                },
238            ],
239            adapters: vec![],
240        }
241    }
242}
243
244/// Configuration manager
245///
246/// Responsible for loading, saving and managing configuration information
247pub struct ConfigManager {
248    /// Current settings
249    config: GaiaSettings,
250    /// Configuration file path
251    config_path: Option<String>,
252}
253
254impl ConfigManager {
255    /// Create a new configuration manager
256    pub fn new() -> Self {
257        Self { config: GaiaSettings::default(), config_path: None }
258    }
259
260    /// Load configuration from file
261    ///
262    /// # Parameters
263    /// * `path` - Path to the configuration file
264    ///
265    /// # Return Value
266    /// Returns Ok(()) on success, or an error message on failure.
267    pub fn load_from_file<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
268        let path = path.as_ref();
269        let content = fs::read_to_string(path).map_err(|e| {
270            GaiaError::config_error(Some(path.to_string_lossy()), format!("Failed to read configuration file: {}", e))
271        })?;
272
273        self.config = toml::from_str(&content).map_err(|e| {
274            GaiaError::config_error(Some(path.to_string_lossy()), format!("Failed to parse configuration file: {}", e))
275        })?;
276
277        self.config_path = Some(path.to_string_lossy().to_string());
278        Ok(())
279    }
280
281    /// Save configuration to file
282    ///
283    /// # Parameters
284    /// * `path` - Path to the configuration file
285    ///
286    /// # Return Value
287    /// Returns Ok(()) on success, or an error message on failure.
288    pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
289        let path = path.as_ref();
290        let content = toml::to_string_pretty(&self.config).map_err(|e| {
291            GaiaError::config_error(Some(path.to_string_lossy()), format!("Failed to serialize configuration: {}", e))
292        })?;
293
294        fs::write(path, content).map_err(|e| {
295            GaiaError::config_error(Some(path.to_string_lossy()), format!("Failed to write configuration file: {}", e))
296        })?;
297
298        Ok(())
299    }
300
301    /// Get current settings
302    pub fn settings(&self) -> &GaiaSettings {
303        &self.config
304    }
305
306    /// Get current settings (legacy compatibility)
307    pub fn config(&self) -> &GaiaSettings {
308        &self.config
309    }
310
311    /// Get global setting
312    pub fn get_global_setting(&self, key: &str) -> Option<&str> {
313        self.config.global.parameters.get(key).map(|s| s.as_str())
314    }
315
316    /// Set global setting
317    pub fn set_global_setting(&mut self, key: String, value: String) {
318        self.config.global.parameters.insert(key, value);
319    }
320
321    /// Get platform configuration
322    pub fn get_platform_config(&self, target: &CompilationTarget) -> Option<&PlatformConfig> {
323        self.config.platforms.get(target)
324    }
325
326    /// Add platform configuration
327    pub fn add_platform_config(&mut self, target: CompilationTarget, config: PlatformConfig) {
328        self.config.platforms.insert(target, config);
329    }
330
331    /// Add adapter configuration
332    pub fn add_adapter_config(&mut self, config: AdapterConfigEntry) {
333        self.config.adapters.push(config);
334    }
335
336    /// Get adapter configuration
337    pub fn get_adapter_config(&self, name: &str) -> Option<&AdapterConfigEntry> {
338        self.config.adapters.iter().find(|a| a.name == name)
339    }
340
341    /// Add function mapping
342    pub fn add_function_mapping(&mut self, mapping: FunctionMapping) {
343        self.config.function_mappings.push(mapping);
344    }
345
346    /// Get function mapping
347    pub fn get_function_mapping(&self, common_name: &str, platform: &str) -> Option<&str> {
348        self.config
349            .function_mappings
350            .iter()
351            .find(|m| m.common_name == common_name)
352            .and_then(|m| m.platform_mappings.get(platform).map(|s| s.as_str()))
353    }
354
355    /// Validate configuration
356    pub fn validate(&self) -> Result<()> {
357        Ok(())
358    }
359
360    /// Get current configuration file path
361    pub fn config_path(&self) -> Option<&str> {
362        self.config_path.as_deref()
363    }
364}