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