1use serde::{Deserialize, Serialize};
7use std::collections::{HashMap, HashSet};
8use std::path::{Path, PathBuf};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct CompilationAnalysis {
13 pub dependencies: HashMap<String, Vec<String>>,
15 pub module_sizes: HashMap<String, usize>,
17 pub compilation_times: HashMap<String, f64>,
19 pub heavy_dependencies: HashSet<String>,
21 pub circular_dependencies: Vec<Vec<String>>,
23 pub recommendations: Vec<OptimizationRecommendation>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct OptimizationRecommendation {
30 pub optimization_type: OptimizationType,
32 pub modules: Vec<String>,
34 pub expected_improvement: f64,
36 pub description: String,
38 pub priority: RecommendationPriority,
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
44pub enum OptimizationType {
45 RemoveUnusedImports,
47 ModuleRefactoring,
49 LazyImports,
51 FeatureOptimization,
53 MacroOptimization,
55 DynamicLoading,
57 ParallelCompilation,
59 IncrementalCompilation,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
65pub enum RecommendationPriority {
66 Low,
68 Medium,
70 High,
72 Critical,
74}
75
76#[derive(Debug, Clone)]
78pub struct CompilationOptimizerConfig {
79 pub root_path: PathBuf,
81 pub file_extensions: Vec<String>,
83 pub max_module_size: usize,
85 pub heavy_dependency_threshold: f64,
87 pub enable_advanced_analysis: bool,
89}
90
91impl Default for CompilationOptimizerConfig {
92 fn default() -> Self {
93 Self {
94 root_path: PathBuf::from("."),
95 file_extensions: vec!["rs".to_string()],
96 max_module_size: 2000,
97 heavy_dependency_threshold: 5.0,
98 enable_advanced_analysis: true,
99 }
100 }
101}
102
103pub struct CompilationOptimizer {
105 config: CompilationOptimizerConfig,
107 analysis_cache: HashMap<String, CompilationAnalysis>,
109}
110
111impl CompilationOptimizer {
112 pub fn new(config: CompilationOptimizerConfig) -> Self {
114 Self {
115 config,
116 analysis_cache: HashMap::new(),
117 }
118 }
119
120 pub fn analyze_codebase(&mut self) -> Result<CompilationAnalysis, Box<dyn std::error::Error>> {
122 let mut analysis = CompilationAnalysis {
123 dependencies: HashMap::new(),
124 module_sizes: HashMap::new(),
125 compilation_times: HashMap::new(),
126 heavy_dependencies: HashSet::new(),
127 circular_dependencies: Vec::new(),
128 recommendations: Vec::new(),
129 };
130
131 self.analyze_module_structure(&mut analysis)?;
133
134 self.analyze_dependencies(&mut analysis)?;
136
137 self.detect_compilation_bottlenecks(&mut analysis)?;
139
140 self.generate_recommendations(&mut analysis)?;
142
143 Ok(analysis)
144 }
145
146 fn analyze_module_structure(
148 &self,
149 analysis: &mut CompilationAnalysis,
150 ) -> Result<(), Box<dyn std::error::Error>> {
151 use std::fs;
152
153 fn visit_files(
154 dir: &Path,
155 extensions: &[String],
156 analysis: &mut CompilationAnalysis,
157 ) -> Result<(), Box<dyn std::error::Error>> {
158 if dir.is_dir() {
159 for entry in fs::read_dir(dir)? {
160 let entry = entry?;
161 let path = entry.path();
162
163 if path.is_dir() {
164 visit_files(&path, extensions, analysis)?;
165 } else if let Some(ext) = path.extension() {
166 if extensions.contains(&ext.to_string_lossy().to_string()) {
167 let content = fs::read_to_string(&path)?;
168 let line_count = content.lines().count();
169
170 let module_name = path
171 .file_stem()
172 .unwrap_or_default()
173 .to_string_lossy()
174 .to_string();
175
176 analysis.module_sizes.insert(module_name, line_count);
177 }
178 }
179 }
180 }
181 Ok(())
182 }
183
184 visit_files(
185 &self.config.root_path,
186 &self.config.file_extensions,
187 analysis,
188 )?;
189 Ok(())
190 }
191
192 fn analyze_dependencies(
194 &self,
195 analysis: &mut CompilationAnalysis,
196 ) -> Result<(), Box<dyn std::error::Error>> {
197 use regex::Regex;
198 use std::fs;
199
200 let use_regex = Regex::new(r"^use\s+([^;]+);").unwrap();
201 let mod_regex = Regex::new(r"^(?:pub\s+)?mod\s+(\w+)").unwrap();
202
203 for (module_name, _) in &analysis.module_sizes {
204 let mut module_path = self.config.root_path.clone();
205 module_path.push(format!("{}.rs", module_name));
206
207 if let Ok(content) = fs::read_to_string(&module_path) {
208 let mut dependencies = Vec::new();
209
210 for line in content.lines() {
211 let line = line.trim();
212
213 if let Some(captures) = use_regex.captures(line) {
215 let use_path = captures.get(1).unwrap().as_str();
216 if let Some(first_component) = use_path.split("::").next() {
218 if first_component.starts_with("crate::") {
219 let module = first_component
220 .strip_prefix("crate::")
221 .unwrap_or(first_component);
222 dependencies.push(module.to_string());
223 }
224 }
225 }
226
227 if let Some(captures) = mod_regex.captures(line) {
229 let mod_name = captures.get(1).unwrap().as_str();
230 dependencies.push(mod_name.to_string());
231 }
232 }
233
234 analysis
235 .dependencies
236 .insert(module_name.clone(), dependencies);
237 }
238 }
239
240 Ok(())
241 }
242
243 fn detect_compilation_bottlenecks(
245 &self,
246 analysis: &mut CompilationAnalysis,
247 ) -> Result<(), Box<dyn std::error::Error>> {
248 for (module_name, &size) in &analysis.module_sizes {
250 let base_time = size as f64 * 0.001; let dependency_count = analysis
254 .dependencies
255 .get(module_name)
256 .map(|deps| deps.len())
257 .unwrap_or(0);
258 let dependency_penalty = dependency_count as f64 * 0.1;
259
260 let complexity_penalty = if size > 1000 {
262 size as f64 * 0.0005
263 } else {
264 0.0
265 };
266
267 let estimated_time = base_time + dependency_penalty + complexity_penalty;
268 analysis
269 .compilation_times
270 .insert(module_name.clone(), estimated_time);
271
272 if estimated_time > self.config.heavy_dependency_threshold {
274 analysis.heavy_dependencies.insert(module_name.clone());
275 }
276 }
277
278 self.detect_circular_dependencies(analysis);
280
281 Ok(())
282 }
283
284 fn detect_circular_dependencies(&self, analysis: &mut CompilationAnalysis) {
286 let mut visited = HashSet::new();
287 let mut rec_stack = HashSet::new();
288 let mut path = Vec::new();
289
290 for module in analysis.dependencies.keys() {
291 if !visited.contains(module) {
292 self.dfs_cycle_detection(
293 module,
294 &analysis.dependencies,
295 &mut visited,
296 &mut rec_stack,
297 &mut path,
298 &mut analysis.circular_dependencies,
299 );
300 }
301 }
302 }
303
304 fn dfs_cycle_detection(
306 &self,
307 module: &str,
308 dependencies: &HashMap<String, Vec<String>>,
309 visited: &mut HashSet<String>,
310 rec_stack: &mut HashSet<String>,
311 path: &mut Vec<String>,
312 cycles: &mut Vec<Vec<String>>,
313 ) {
314 visited.insert(module.to_string());
315 rec_stack.insert(module.to_string());
316 path.push(module.to_string());
317
318 if let Some(deps) = dependencies.get(module) {
319 for dep in deps {
320 if !visited.contains(dep) {
321 self.dfs_cycle_detection(dep, dependencies, visited, rec_stack, path, cycles);
322 } else if rec_stack.contains(dep) {
323 if let Some(cycle_start) = path.iter().position(|m| m == dep) {
325 let cycle = path[cycle_start..].to_vec();
326 cycles.push(cycle);
327 }
328 }
329 }
330 }
331
332 rec_stack.remove(module);
333 path.pop();
334 }
335
336 fn generate_recommendations(
338 &self,
339 analysis: &mut CompilationAnalysis,
340 ) -> Result<(), Box<dyn std::error::Error>> {
341 for (module_name, &size) in &analysis.module_sizes {
343 if size > self.config.max_module_size {
344 analysis.recommendations.push(OptimizationRecommendation {
345 optimization_type: OptimizationType::ModuleRefactoring,
346 modules: vec![module_name.clone()],
347 expected_improvement: (size as f64 - self.config.max_module_size as f64)
348 * 0.001,
349 description: format!(
350 "Module '{}' has {} lines and should be split into smaller modules",
351 module_name, size
352 ),
353 priority: if size > self.config.max_module_size * 2 {
354 RecommendationPriority::High
355 } else {
356 RecommendationPriority::Medium
357 },
358 });
359 }
360 }
361
362 for heavy_dep in &analysis.heavy_dependencies {
364 let compile_time = analysis.compilation_times.get(heavy_dep).unwrap_or(&0.0);
365 analysis.recommendations.push(OptimizationRecommendation {
366 optimization_type: OptimizationType::LazyImports,
367 modules: vec![heavy_dep.clone()],
368 expected_improvement: compile_time * 0.3, description: format!(
370 "Module '{}' has high compilation time ({:.2}s) and could benefit from lazy imports",
371 heavy_dep, compile_time
372 ),
373 priority: RecommendationPriority::Medium,
374 });
375 }
376
377 for cycle in &analysis.circular_dependencies {
379 analysis.recommendations.push(OptimizationRecommendation {
380 optimization_type: OptimizationType::ModuleRefactoring,
381 modules: cycle.clone(),
382 expected_improvement: 2.0, description: format!("Circular dependency detected: {}", cycle.join(" -> ")),
384 priority: RecommendationPriority::High,
385 });
386 }
387
388 analysis.recommendations.sort_by(|a, b| {
390 b.priority.cmp(&a.priority).then_with(|| {
391 b.expected_improvement
392 .partial_cmp(&a.expected_improvement)
393 .unwrap_or(std::cmp::Ordering::Equal)
394 })
395 });
396
397 Ok(())
398 }
399
400 pub fn apply_optimizations(
402 &self,
403 analysis: &CompilationAnalysis,
404 ) -> Result<Vec<String>, Box<dyn std::error::Error>> {
405 let mut applied_optimizations = Vec::new();
406
407 for recommendation in &analysis.recommendations {
408 match recommendation.optimization_type {
409 OptimizationType::RemoveUnusedImports => {
410 if self.apply_unused_import_removal(&recommendation.modules)? {
411 applied_optimizations.push(format!(
412 "Removed unused imports from modules: {}",
413 recommendation.modules.join(", ")
414 ));
415 }
416 }
417 OptimizationType::FeatureOptimization => {
418 if self.apply_feature_optimization(&recommendation.modules)? {
419 applied_optimizations.push(format!(
420 "Optimized feature flags for modules: {}",
421 recommendation.modules.join(", ")
422 ));
423 }
424 }
425 _ => {
426 applied_optimizations.push(format!(
428 "Manual optimization needed: {}",
429 recommendation.description
430 ));
431 }
432 }
433 }
434
435 Ok(applied_optimizations)
436 }
437
438 fn apply_unused_import_removal(
440 &self,
441 _modules: &[String],
442 ) -> Result<bool, Box<dyn std::error::Error>> {
443 Ok(true)
446 }
447
448 fn apply_feature_optimization(
450 &self,
451 _modules: &[String],
452 ) -> Result<bool, Box<dyn std::error::Error>> {
453 Ok(true)
455 }
456
457 pub fn generate_report(&self, analysis: &CompilationAnalysis) -> String {
459 let mut report = String::new();
460
461 report.push_str("# Compilation Optimization Report\n\n");
462
463 report.push_str("## Module Statistics\n");
465 let total_modules = analysis.module_sizes.len();
466 let total_lines: usize = analysis.module_sizes.values().sum();
467 let average_size = if total_modules > 0 {
468 total_lines / total_modules
469 } else {
470 0
471 };
472
473 report.push_str(&format!("- Total modules: {}\n", total_modules));
474 report.push_str(&format!("- Total lines of code: {}\n", total_lines));
475 report.push_str(&format!("- Average module size: {} lines\n", average_size));
476 report.push_str(&format!(
477 "- Heavy dependencies: {}\n",
478 analysis.heavy_dependencies.len()
479 ));
480 report.push_str(&format!(
481 "- Circular dependencies: {}\n\n",
482 analysis.circular_dependencies.len()
483 ));
484
485 let mut modules_by_size: Vec<_> = analysis.module_sizes.iter().collect();
487 modules_by_size.sort_by(|a, b| b.1.cmp(a.1));
488
489 report.push_str("## Largest Modules\n");
490 for (module, size) in modules_by_size.iter().take(10) {
491 report.push_str(&format!("- {}: {} lines\n", module, size));
492 }
493 report.push_str("\n");
494
495 report.push_str("## Optimization Recommendations\n");
497 for (i, rec) in analysis.recommendations.iter().enumerate() {
498 report.push_str(&format!(
499 "{}. **{:?}** (Priority: {:?})\n - Modules: {}\n - Expected improvement: {:.2}s\n - {}\n\n",
500 i + 1,
501 rec.optimization_type,
502 rec.priority,
503 rec.modules.join(", "),
504 rec.expected_improvement,
505 rec.description
506 ));
507 }
508
509 report
510 }
511}
512
513pub mod utils {
515 use super::*;
516
517 pub fn estimate_total_compilation_time(analysis: &CompilationAnalysis) -> f64 {
519 analysis.compilation_times.values().sum()
520 }
521
522 pub fn calculate_potential_savings(analysis: &CompilationAnalysis) -> f64 {
524 analysis
525 .recommendations
526 .iter()
527 .map(|rec| rec.expected_improvement)
528 .sum()
529 }
530
531 pub fn get_efficiency_score(analysis: &CompilationAnalysis) -> f64 {
533 let total_time = estimate_total_compilation_time(analysis);
534 let potential_savings = calculate_potential_savings(analysis);
535
536 if total_time > 0.0 {
537 1.0 - (potential_savings / total_time).min(1.0)
538 } else {
539 1.0
540 }
541 }
542
543 pub fn create_quantum_sim_config(root_path: &Path) -> CompilationOptimizerConfig {
545 CompilationOptimizerConfig {
546 root_path: root_path.to_path_buf(),
547 file_extensions: vec!["rs".to_string()],
548 max_module_size: 2000, heavy_dependency_threshold: 3.0,
550 enable_advanced_analysis: true,
551 }
552 }
553}
554
555#[cfg(test)]
556mod tests {
557 use super::*;
558 use std::fs;
559 use tempfile::TempDir;
560
561 #[test]
562 fn test_compilation_optimizer() {
563 let temp_dir = TempDir::new().unwrap();
564 let config = CompilationOptimizerConfig {
565 root_path: temp_dir.path().to_path_buf(),
566 ..Default::default()
567 };
568
569 fs::write(
571 temp_dir.path().join("large_module.rs"),
572 "use std::collections::HashMap;\n".repeat(3000),
573 )
574 .unwrap();
575
576 fs::write(
577 temp_dir.path().join("small_module.rs"),
578 "use std::vec::Vec;\n".repeat(100),
579 )
580 .unwrap();
581
582 let mut optimizer = CompilationOptimizer::new(config);
583 let analysis = optimizer.analyze_codebase().unwrap();
584
585 assert!(analysis.module_sizes.contains_key("large_module"));
586 assert!(analysis.module_sizes.contains_key("small_module"));
587 assert!(!analysis.recommendations.is_empty());
588 }
589
590 #[test]
591 fn test_optimization_recommendations() {
592 let mut analysis = CompilationAnalysis {
593 dependencies: HashMap::new(),
594 module_sizes: HashMap::new(),
595 compilation_times: HashMap::new(),
596 heavy_dependencies: HashSet::new(),
597 circular_dependencies: Vec::new(),
598 recommendations: Vec::new(),
599 };
600
601 analysis
603 .module_sizes
604 .insert("large_module".to_string(), 5000);
605 analysis
606 .compilation_times
607 .insert("large_module".to_string(), 10.0);
608
609 let config = CompilationOptimizerConfig::default();
610 let optimizer = CompilationOptimizer::new(config);
611 optimizer.generate_recommendations(&mut analysis).unwrap();
612
613 assert!(!analysis.recommendations.is_empty());
614 assert!(analysis
615 .recommendations
616 .iter()
617 .any(|rec| { rec.optimization_type == OptimizationType::ModuleRefactoring }));
618 }
619
620 #[test]
621 fn test_efficiency_calculation() {
622 let mut analysis = CompilationAnalysis {
623 dependencies: HashMap::new(),
624 module_sizes: HashMap::new(),
625 compilation_times: HashMap::new(),
626 heavy_dependencies: HashSet::new(),
627 circular_dependencies: Vec::new(),
628 recommendations: Vec::new(),
629 };
630
631 analysis
632 .compilation_times
633 .insert("module1".to_string(), 5.0);
634 analysis
635 .compilation_times
636 .insert("module2".to_string(), 3.0);
637
638 analysis.recommendations.push(OptimizationRecommendation {
639 optimization_type: OptimizationType::ModuleRefactoring,
640 modules: vec!["module1".to_string()],
641 expected_improvement: 2.0,
642 description: "Test".to_string(),
643 priority: RecommendationPriority::Medium,
644 });
645
646 let efficiency = utils::get_efficiency_score(&analysis);
647 assert!(efficiency > 0.0 && efficiency <= 1.0);
648 }
649}