Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-core/src/config.rs
StratoSDK / crates / strato-core / src / config.rs
1//! Configuration system for StratoUI framework
2 
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::sync::{Arc, OnceLock, RwLock};
6 
7/// Global configuration for StratoUI
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct StratoConfig {
10 /// Logging configuration
11 pub logging: LoggingConfig,
12 /// Performance and optimization settings
13 pub performance: PerformanceConfig,
14 /// Debug and development settings
15 pub debug: DebugConfig,
16}
17 
18/// Logging configuration
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct LoggingConfig {
21 /// Category-specific log levels (category name -> level string)
22 pub category_levels: HashMap<String, String>,
23 /// Rate limiting duration in seconds
24 pub rate_limit_seconds: u64,
25 /// Maximum number of messages before rate limiting kicks in
26 pub max_rate_limit_count: u32,
27 /// Enable text rendering debug logs
28 pub enable_text_debug: bool,
29 /// Enable layout debug logs
30 pub enable_layout_debug: bool,
31}
32 
33/// Performance configuration
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct PerformanceConfig {
36 /// Enable GPU profiling
37 pub enable_gpu_profiling: bool,
38 /// Enable CPU profiling
39 pub enable_cpu_profiling: bool,
40 /// Maximum frame rate (0 = unlimited)
41 pub max_fps: u32,
42 /// Enable VSync
43 pub enable_vsync: bool,
44}
45 
46/// Debug configuration
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct DebugConfig {
49 /// Show debug overlay
50 pub show_debug_overlay: bool,
51 /// Show frame timing information
52 pub show_frame_timing: bool,
53 /// Show memory usage
54 pub show_memory_usage: bool,
55 /// Enable wireframe rendering
56 pub enable_wireframe: bool,
57}
58 
59impl Default for StratoConfig {
60 fn default() -> Self {
61 let mut category_levels = HashMap::new();
62 
63 // Set default levels for each category
64 category_levels.insert("core".to_string(), "info".to_string());
65 category_levels.insert("renderer".to_string(), "info".to_string());
66 category_levels.insert("ui".to_string(), "info".to_string());
67 category_levels.insert("input".to_string(), "info".to_string());
68 category_levels.insert("audio".to_string(), "info".to_string());
69 category_levels.insert("network".to_string(), "info".to_string());
70 category_levels.insert("vulkan".to_string(), "warn".to_string()); // Reduce Vulkan noise
71 category_levels.insert("text".to_string(), "error".to_string()); // Disable text debug by default
72 category_levels.insert("layout".to_string(), "error".to_string()); // Disable layout debug by default
73 
74 Self {
75 logging: LoggingConfig {
76 category_levels,
77 enable_text_debug: false,
78 enable_layout_debug: false,
79 rate_limit_seconds: 5,
80 max_rate_limit_count: 10,
81 },
82 performance: PerformanceConfig {
83 enable_gpu_profiling: false,
84 enable_cpu_profiling: false,
85 max_fps: 60,
86 enable_vsync: true,
87 },
88 debug: DebugConfig {
89 show_debug_overlay: false,
90 show_frame_timing: false,
91 show_memory_usage: false,
92 enable_wireframe: false,
93 },
94 }
95 }
96}
97 
98impl Default for LoggingConfig {
99 fn default() -> Self {
100 StratoConfig::default().logging
101 }
102}
103 
104impl Default for PerformanceConfig {
105 fn default() -> Self {
106 StratoConfig::default().performance
107 }
108}
109 
110impl Default for DebugConfig {
111 fn default() -> Self {
112 StratoConfig::default().debug
113 }
114}
115 
116/// Global configuration manager
117pub struct ConfigManager {
118 config: Arc<RwLock<StratoConfig>>,
119}
120 
121impl ConfigManager {
122 /// Create a new configuration manager with default settings
123 pub fn new() -> Self {
124 Self {
125 config: Arc::new(RwLock::new(StratoConfig::default())),
126 }
127 }
128 
129 /// Create a configuration manager with custom config
130 pub fn with_config(config: StratoConfig) -> Self {
131 Self {
132 config: Arc::new(RwLock::new(config)),
133 }
134 }
135 
136 /// Get the global configuration manager instance
137 pub fn instance() -> Option<&'static ConfigManager> {
138 CONFIG_MANAGER.get()
139 }
140 
141 /// Get a copy of the current configuration
142 pub fn get_config(&self) -> StratoConfig {
143 self.config.read().unwrap().clone()
144 }
145 
146 /// Update the configuration
147 pub fn update_config<F>(&self, updater: F)
148 where
149 F: FnOnce(&mut StratoConfig),
150 {
151 let mut config = self.config.write().unwrap();
152 updater(&mut *config);
153 }
154 
155 /// Get the current logging configuration
156 pub fn get_logging_config(&self) -> LoggingConfig {
157 self.config.read().unwrap().logging.clone()
158 }
159 
160 /// Update logging configuration
161 pub fn update_logging_config<F>(&self, updater: F)
162 where
163 F: FnOnce(&mut LoggingConfig),
164 {
165 let mut config = self.config.write().unwrap();
166 updater(&mut config.logging);
167 }
168 
169 /// Enable or disable text debug logging
170 pub fn set_text_debug(&self, enabled: bool) {
171 self.update_logging_config(|logging| {
172 logging.enable_text_debug = enabled;
173 if enabled {
174 logging
175 .category_levels
176 .insert("text".to_string(), "debug".to_string());
177 } else {
178 logging
179 .category_levels
180 .insert("text".to_string(), "error".to_string());
181 }
182 });
183 }
184 
185 /// Enable or disable layout debug logging
186 pub fn set_layout_debug(&self, enabled: bool) {
187 self.update_logging_config(|logging| {
188 logging.enable_layout_debug = enabled;
189 if enabled {
190 logging
191 .category_levels
192 .insert("layout".to_string(), "debug".to_string());
193 } else {
194 logging
195 .category_levels
196 .insert("layout".to_string(), "error".to_string());
197 }
198 });
199 }
200 
201 /// Set log level for a specific category
202 pub fn set_category_level(&self, category: &str, level: &str) {
203 self.update_logging_config(|logging| {
204 logging
205 .category_levels
206 .insert(category.to_string(), level.to_string());
207 });
208 }
209 
210 /// Get log level for a specific category
211 pub fn get_category_level(&self, category: &str) -> Option<String> {
212 let config = self.config.read().unwrap();
213 config.logging.category_levels.get(category).cloned()
214 }
215}
216 
217impl Default for ConfigManager {
218 fn default() -> Self {
219 Self::new()
220 }
221}
222 
223/// Global configuration instance
224static CONFIG_MANAGER: OnceLock<ConfigManager> = OnceLock::new();
225 
226/// Initialize the global configuration manager
227pub fn init_config() -> &'static ConfigManager {
228 CONFIG_MANAGER.get_or_init(ConfigManager::new)
229}
230 
231/// Initialize the global configuration manager with custom config
232pub fn init_config_with(config: StratoConfig) -> &'static ConfigManager {
233 CONFIG_MANAGER.get_or_init(|| ConfigManager::with_config(config))
234}
235 
236/// Get the global configuration manager
237pub fn get_config_manager() -> Option<&'static ConfigManager> {
238 CONFIG_MANAGER.get()
239}
240 
241#[cfg(test)]
242mod tests {
243 use super::*;
244 
245 #[test]
246 fn test_default_config() {
247 let config = StratoConfig::default();
248 
249 assert!(!config.logging.enable_text_debug);
250 assert!(!config.logging.enable_layout_debug);
251 
252 // Text and Layout should be disabled by default
253 assert_eq!(
254 config.logging.category_levels.get("text"),
255 Some(&"error".to_string())
256 );
257 assert_eq!(
258 config.logging.category_levels.get("layout"),
259 Some(&"error".to_string())
260 );
261 
262 // Vulkan should be at Warn level to reduce noise
263 assert_eq!(
264 config.logging.category_levels.get("vulkan"),
265 Some(&"warn".to_string())
266 );
267 }
268 
269 #[test]
270 fn test_config_manager() {
271 let manager = ConfigManager::new();
272 
273 // Test text debug toggle
274 manager.set_text_debug(true);
275 assert_eq!(
276 manager.get_category_level("text"),
277 Some("debug".to_string())
278 );
279 
280 manager.set_text_debug(false);
281 assert_eq!(
282 manager.get_category_level("text"),
283 Some("error".to_string())
284 );
285 
286 // Test category level setting
287 manager.set_category_level("renderer", "trace");
288 assert_eq!(
289 manager.get_category_level("renderer"),
290 Some("trace".to_string())
291 );
292 }
293}
294