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 = if total_modules > 0 {
475 total_lines / total_modules
476 } else {
477 0
478 };
479
480 let _ = writeln!(report, "- Total modules: {total_modules}");
482 let _ = writeln!(report, "- Total lines of code: {total_lines}");
483 let _ = writeln!(report, "- Average module size: {average_size} lines");
484 let _ = writeln!(
485 report,
486 "- Heavy dependencies: {}",
487 analysis.heavy_dependencies.len()
488 );
489 let _ = write!(
490 report,
491 "- Circular dependencies: {}\n\n",
492 analysis.circular_dependencies.len()
493 );
494
495 let mut modules_by_size: Vec<_> = analysis.module_sizes.iter().collect();
497 modules_by_size.sort_by(|a, b| b.1.cmp(a.1));
498
499 report.push_str("## Largest Modules\n");
500 for (module, size) in modules_by_size.iter().take(10) {
501 let _ = writeln!(report, "- {module}: {size} lines");
502 }
503 report.push('\n');
504
505 report.push_str("## Optimization Recommendations\n");
507 for (i, rec) in analysis.recommendations.iter().enumerate() {
508 let _ = write!(report, "{}. **{:?}** (Priority: {:?})\n - Modules: {}\n - Expected improvement: {:.2}s\n - {}\n\n",
509 i + 1,
510 rec.optimization_type,
511 rec.priority,
512 rec.modules.join(", "),
513 rec.expected_improvement,
514 rec.description);
515 }
516
517 report
518 }
519}
520
521pub mod utils {
523 use super::{CompilationAnalysis, CompilationOptimizerConfig, Path};
524
525 #[must_use]
527 pub fn estimate_total_compilation_time(analysis: &CompilationAnalysis) -> f64 {
528 analysis.compilation_times.values().sum()
529 }
530
531 #[must_use]
533 pub fn calculate_potential_savings(analysis: &CompilationAnalysis) -> f64 {
534 analysis
535 .recommendations
536 .iter()
537 .map(|rec| rec.expected_improvement)
538 .sum()
539 }
540
541 #[must_use]
543 pub fn get_efficiency_score(analysis: &CompilationAnalysis) -> f64 {
544 let total_time = estimate_total_compilation_time(analysis);
545 let potential_savings = calculate_potential_savings(analysis);
546
547 if total_time > 0.0 {
548 1.0 - (potential_savings / total_time).min(1.0)
549 } else {
550 1.0
551 }
552 }
553
554 #[must_use]
556 pub fn create_quantum_sim_config(root_path: &Path) -> CompilationOptimizerConfig {
557 CompilationOptimizerConfig {
558 root_path: root_path.to_path_buf(),
559 file_extensions: vec!["rs".to_string()],
560 max_module_size: 2000, heavy_dependency_threshold: 3.0,
562 enable_advanced_analysis: true,
563 }
564 }
565}
566
567#[cfg(test)]
568mod tests {
569 use super::*;
570 use std::fs;
571 use tempfile::TempDir;
572
573 #[test]
574 fn test_compilation_optimizer() {
575 let temp_dir = TempDir::new().expect("Failed to create temp directory");
576 let config = CompilationOptimizerConfig {
577 root_path: temp_dir.path().to_path_buf(),
578 ..Default::default()
579 };
580
581 fs::write(
583 temp_dir.path().join("large_module.rs"),
584 "use std::collections::HashMap;\n".repeat(3000),
585 )
586 .expect("Failed to write large_module.rs");
587
588 fs::write(
589 temp_dir.path().join("small_module.rs"),
590 "use std::vec::Vec;\n".repeat(100),
591 )
592 .expect("Failed to write small_module.rs");
593
594 let mut optimizer = CompilationOptimizer::new(config);
595 let analysis = optimizer
596 .analyze_codebase()
597 .expect("Failed to analyze codebase");
598
599 assert!(analysis.module_sizes.contains_key("large_module"));
600 assert!(analysis.module_sizes.contains_key("small_module"));
601 assert!(!analysis.recommendations.is_empty());
602 }
603
604 #[test]
605 fn test_optimization_recommendations() {
606 let mut analysis = CompilationAnalysis {
607 dependencies: HashMap::new(),
608 module_sizes: HashMap::new(),
609 compilation_times: HashMap::new(),
610 heavy_dependencies: HashSet::new(),
611 circular_dependencies: Vec::new(),
612 recommendations: Vec::new(),
613 };
614
615 analysis
617 .module_sizes
618 .insert("large_module".to_string(), 5000);
619 analysis
620 .compilation_times
621 .insert("large_module".to_string(), 10.0);
622
623 let config = CompilationOptimizerConfig::default();
624 let optimizer = CompilationOptimizer::new(config);
625 optimizer
626 .generate_recommendations(&mut analysis)
627 .expect("Failed to generate recommendations");
628
629 assert!(!analysis.recommendations.is_empty());
630 assert!(analysis
631 .recommendations
632 .iter()
633 .any(|rec| { rec.optimization_type == OptimizationType::ModuleRefactoring }));
634 }
635
636 #[test]
637 fn test_efficiency_calculation() {
638 let mut analysis = CompilationAnalysis {
639 dependencies: HashMap::new(),
640 module_sizes: HashMap::new(),
641 compilation_times: HashMap::new(),
642 heavy_dependencies: HashSet::new(),
643 circular_dependencies: Vec::new(),
644 recommendations: Vec::new(),
645 };
646
647 analysis
648 .compilation_times
649 .insert("module1".to_string(), 5.0);
650 analysis
651 .compilation_times
652 .insert("module2".to_string(), 3.0);
653
654 analysis.recommendations.push(OptimizationRecommendation {
655 optimization_type: OptimizationType::ModuleRefactoring,
656 modules: vec!["module1".to_string()],
657 expected_improvement: 2.0,
658 description: "Test".to_string(),
659 priority: RecommendationPriority::Medium,
660 });
661
662 let efficiency = utils::get_efficiency_score(&analysis);
663 assert!(efficiency > 0.0 && efficiency <= 1.0);
664 }
665}