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