1use 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#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct FunctionMapping {
19 pub common_name: String,
21 pub platform_mappings: HashMap<String, String>,
23 pub description: Option<String>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct PlatformConfig {
32 pub target: CompilationTarget,
34 pub description: Option<String>,
36 pub supported_architectures: Vec<String>,
38 pub default_extension: String,
40 pub parameters: HashMap<String, String>,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct AdapterConfigEntry {
49 pub name: String,
51 pub adapter_type: String,
53 pub compilation_target: CompilationTarget,
55 pub enabled: bool,
57 pub parameters: HashMap<String, String>,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct GlobalConfig {
66 pub default_output_dir: String,
68 pub debug_mode: bool,
70 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 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#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct GaiaSettings {
103 pub version: String,
105 pub global: GlobalConfig,
107 #[serde(with = "target_map_serde")]
109 pub platforms: HashMap<CompilationTarget, PlatformConfig>,
110 pub function_mappings: Vec<FunctionMapping>,
112 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 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
242pub struct ConfigManager {
246 config: GaiaSettings,
248 config_path: Option<String>,
250}
251
252impl ConfigManager {
253 pub fn new() -> Self {
255 Self { config: GaiaSettings::default(), config_path: None }
256 }
257
258 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 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 pub fn settings(&self) -> &GaiaSettings {
301 &self.config
302 }
303
304 pub fn config(&self) -> &GaiaSettings {
306 &self.config
307 }
308
309 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 pub fn set_global_setting(&mut self, key: String, value: String) {
316 self.config.global.parameters.insert(key, value);
317 }
318
319 pub fn get_platform_config(&self, target: &CompilationTarget) -> Option<&PlatformConfig> {
321 self.config.platforms.get(target)
322 }
323
324 pub fn add_platform_config(&mut self, target: CompilationTarget, config: PlatformConfig) {
326 self.config.platforms.insert(target, config);
327 }
328
329 pub fn add_adapter_config(&mut self, config: AdapterConfigEntry) {
331 self.config.adapters.push(config);
332 }
333
334 pub fn get_adapter_config(&self, name: &str) -> Option<&AdapterConfigEntry> {
336 self.config.adapters.iter().find(|a| a.name == name)
337 }
338
339 pub fn add_function_mapping(&mut self, mapping: FunctionMapping) {
341 self.config.function_mappings.push(mapping);
342 }
343
344 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 pub fn validate(&self) -> Result<()> {
355 Ok(())
356 }
357
358 pub fn config_path(&self) -> Option<&str> {
360 self.config_path.as_deref()
361 }
362}