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.keys() {
204 let mut module_path = self.config.root_path.clone();
205 module_path.push(format!("{module_name}.rs"));
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_or(0, |deps| deps.len());
257 let dependency_penalty = dependency_count as f64 * 0.1;
258
259 let complexity_penalty = if size > 1000 {
261 size as f64 * 0.0005
262 } else {
263 0.0
264 };
265
266 let estimated_time = base_time + dependency_penalty + complexity_penalty;
267 analysis
268 .compilation_times
269 .insert(module_name.clone(), estimated_time);
270
271 if estimated_time > self.config.heavy_dependency_threshold {
273 analysis.heavy_dependencies.insert(module_name.clone());
274 }
275 }
276
277 self.detect_circular_dependencies(analysis);
279
280 Ok(())
281 }
282
283 fn detect_circular_dependencies(&self, analysis: &mut CompilationAnalysis) {
285 let mut visited = HashSet::new();
286 let mut rec_stack = HashSet::new();
287 let mut path = Vec::new();
288
289 for module in analysis.dependencies.keys() {
290 if !visited.contains(module) {
291 self.dfs_cycle_detection(
292 module,
293 &analysis.dependencies,
294 &mut visited,
295 &mut rec_stack,
296 &mut path,
297 &mut analysis.circular_dependencies,
298 );
299 }
300 }
301 }
302
303 fn dfs_cycle_detection(
305 &self,
306 module: &str,
307 dependencies: &HashMap<String, Vec<String>>,
308 visited: &mut HashSet<String>,
309 rec_stack: &mut HashSet<String>,
310 path: &mut Vec<String>,
311 cycles: &mut Vec<Vec<String>>,
312 ) {
313 visited.insert(module.to_string());
314 rec_stack.insert(module.to_string());
315 path.push(module.to_string());
316
317 if let Some(deps) = dependencies.get(module) {
318 for dep in deps {
319 if !visited.contains(dep) {
320 self.dfs_cycle_detection(dep, dependencies, visited, rec_stack, path, cycles);
321 } else if rec_stack.contains(dep) {
322 if let Some(cycle_start) = path.iter().position(|m| m == dep) {
324 let cycle = path[cycle_start..].to_vec();
325 cycles.push(cycle);
326 }
327 }
328 }
329 }
330
331 rec_stack.remove(module);
332 path.pop();
333 }
334
335 fn generate_recommendations(
337 &self,
338 analysis: &mut CompilationAnalysis,
339 ) -> Result<(), Box<dyn std::error::Error>> {
340 for (module_name, &size) in &analysis.module_sizes {
342 if size > self.config.max_module_size {
343 analysis.recommendations.push(OptimizationRecommendation {
344 optimization_type: OptimizationType::ModuleRefactoring,
345 modules: vec![module_name.clone()],
346 expected_improvement: (size as f64 - self.config.max_module_size as f64)
347 * 0.001,
348 description: format!(
349 "Module '{module_name}' has {size} lines and should be split into smaller modules"
350 ),
351 priority: if size > self.config.max_module_size * 2 {
352 RecommendationPriority::High
353 } else {
354 RecommendationPriority::Medium
355 },
356 });
357 }
358 }
359
360 for heavy_dep in &analysis.heavy_dependencies {
362 let compile_time = analysis.compilation_times.get(heavy_dep).unwrap_or(&0.0);
363 analysis.recommendations.push(OptimizationRecommendation {
364 optimization_type: OptimizationType::LazyImports,
365 modules: vec![heavy_dep.clone()],
366 expected_improvement: compile_time * 0.3, description: format!(
368 "Module '{heavy_dep}' has high compilation time ({compile_time:.2}s) and could benefit from lazy imports"
369 ),
370 priority: RecommendationPriority::Medium,
371 });
372 }
373
374 for cycle in &analysis.circular_dependencies {
376 analysis.recommendations.push(OptimizationRecommendation {
377 optimization_type: OptimizationType::ModuleRefactoring,
378 modules: cycle.clone(),
379 expected_improvement: 2.0, description: format!("Circular dependency detected: {}", cycle.join(" -> ")),
381 priority: RecommendationPriority::High,
382 });
383 }
384
385 analysis.recommendations.sort_by(|a, b| {
387 b.priority.cmp(&a.priority).then_with(|| {
388 b.expected_improvement
389 .partial_cmp(&a.expected_improvement)
390 .unwrap_or(std::cmp::Ordering::Equal)
391 })
392 });
393
394 Ok(())
395 }
396
397 pub fn apply_optimizations(
399 &self,
400 analysis: &CompilationAnalysis,
401 ) -> Result<Vec<String>, Box<dyn std::error::Error>> {
402 let mut applied_optimizations = Vec::new();
403
404 for recommendation in &analysis.recommendations {
405 match recommendation.optimization_type {
406 OptimizationType::RemoveUnusedImports => {
407 if self.apply_unused_import_removal(&recommendation.modules)? {
408 applied_optimizations.push(format!(
409 "Removed unused imports from modules: {}",
410 recommendation.modules.join(", ")
411 ));
412 }
413 }
414 OptimizationType::FeatureOptimization => {
415 if self.apply_feature_optimization(&recommendation.modules)? {
416 applied_optimizations.push(format!(
417 "Optimized feature flags for modules: {}",
418 recommendation.modules.join(", ")
419 ));
420 }
421 }
422 _ => {
423 applied_optimizations.push(format!(
425 "Manual optimization needed: {}",
426 recommendation.description
427 ));
428 }
429 }
430 }
431
432 Ok(applied_optimizations)
433 }
434
435 fn apply_unused_import_removal(
437 &self,
438 _modules: &[String],
439 ) -> Result<bool, Box<dyn std::error::Error>> {
440 Ok(true)
443 }
444
445 fn apply_feature_optimization(
447 &self,
448 _modules: &[String],
449 ) -> Result<bool, Box<dyn std::error::Error>> {
450 Ok(true)
452 }
453
454 pub fn generate_report(&self, analysis: &CompilationAnalysis) -> String {
456 let mut report = String::new();
457
458 report.push_str("# Compilation Optimization Report\n\n");
459
460 report.push_str("## Module Statistics\n");
462 let total_modules = analysis.module_sizes.len();
463 let total_lines: usize = analysis.module_sizes.values().sum();
464 let average_size = if total_modules > 0 {
465 total_lines / total_modules
466 } else {
467 0
468 };
469
470 report.push_str(&format!("- Total modules: {total_modules}\n"));
471 report.push_str(&format!("- Total lines of code: {total_lines}\n"));
472 report.push_str(&format!("- Average module size: {average_size} lines\n"));
473 report.push_str(&format!(
474 "- Heavy dependencies: {}\n",
475 analysis.heavy_dependencies.len()
476 ));
477 report.push_str(&format!(
478 "- Circular dependencies: {}\n\n",
479 analysis.circular_dependencies.len()
480 ));
481
482 let mut modules_by_size: Vec<_> = analysis.module_sizes.iter().collect();
484 modules_by_size.sort_by(|a, b| b.1.cmp(a.1));
485
486 report.push_str("## Largest Modules\n");
487 for (module, size) in modules_by_size.iter().take(10) {
488 report.push_str(&format!("- {module}: {size} lines\n"));
489 }
490 report.push('\n');
491
492 report.push_str("## Optimization Recommendations\n");
494 for (i, rec) in analysis.recommendations.iter().enumerate() {
495 report.push_str(&format!(
496 "{}. **{:?}** (Priority: {:?})\n - Modules: {}\n - Expected improvement: {:.2}s\n - {}\n\n",
497 i + 1,
498 rec.optimization_type,
499 rec.priority,
500 rec.modules.join(", "),
501 rec.expected_improvement,
502 rec.description
503 ));
504 }
505
506 report
507 }
508}
509
510pub mod utils {
512 use super::*;
513
514 pub fn estimate_total_compilation_time(analysis: &CompilationAnalysis) -> f64 {
516 analysis.compilation_times.values().sum()
517 }
518
519 pub fn calculate_potential_savings(analysis: &CompilationAnalysis) -> f64 {
521 analysis
522 .recommendations
523 .iter()
524 .map(|rec| rec.expected_improvement)
525 .sum()
526 }
527
528 pub fn get_efficiency_score(analysis: &CompilationAnalysis) -> f64 {
530 let total_time = estimate_total_compilation_time(analysis);
531 let potential_savings = calculate_potential_savings(analysis);
532
533 if total_time > 0.0 {
534 1.0 - (potential_savings / total_time).min(1.0)
535 } else {
536 1.0
537 }
538 }
539
540 pub fn create_quantum_sim_config(root_path: &Path) -> CompilationOptimizerConfig {
542 CompilationOptimizerConfig {
543 root_path: root_path.to_path_buf(),
544 file_extensions: vec!["rs".to_string()],
545 max_module_size: 2000, heavy_dependency_threshold: 3.0,
547 enable_advanced_analysis: true,
548 }
549 }
550}
551
552#[cfg(test)]
553mod tests {
554 use super::*;
555 use std::fs;
556 use tempfile::TempDir;
557
558 #[test]
559 fn test_compilation_optimizer() {
560 let temp_dir = TempDir::new().unwrap();
561 let config = CompilationOptimizerConfig {
562 root_path: temp_dir.path().to_path_buf(),
563 ..Default::default()
564 };
565
566 fs::write(
568 temp_dir.path().join("large_module.rs"),
569 "use std::collections::HashMap;\n".repeat(3000),
570 )
571 .unwrap();
572
573 fs::write(
574 temp_dir.path().join("small_module.rs"),
575 "use std::vec::Vec;\n".repeat(100),
576 )
577 .unwrap();
578
579 let mut optimizer = CompilationOptimizer::new(config);
580 let analysis = optimizer.analyze_codebase().unwrap();
581
582 assert!(analysis.module_sizes.contains_key("large_module"));
583 assert!(analysis.module_sizes.contains_key("small_module"));
584 assert!(!analysis.recommendations.is_empty());
585 }
586
587 #[test]
588 fn test_optimization_recommendations() {
589 let mut analysis = CompilationAnalysis {
590 dependencies: HashMap::new(),
591 module_sizes: HashMap::new(),
592 compilation_times: HashMap::new(),
593 heavy_dependencies: HashSet::new(),
594 circular_dependencies: Vec::new(),
595 recommendations: Vec::new(),
596 };
597
598 analysis
600 .module_sizes
601 .insert("large_module".to_string(), 5000);
602 analysis
603 .compilation_times
604 .insert("large_module".to_string(), 10.0);
605
606 let config = CompilationOptimizerConfig::default();
607 let optimizer = CompilationOptimizer::new(config);
608 optimizer.generate_recommendations(&mut analysis).unwrap();
609
610 assert!(!analysis.recommendations.is_empty());
611 assert!(analysis
612 .recommendations
613 .iter()
614 .any(|rec| { rec.optimization_type == OptimizationType::ModuleRefactoring }));
615 }
616
617 #[test]
618 fn test_efficiency_calculation() {
619 let mut analysis = CompilationAnalysis {
620 dependencies: HashMap::new(),
621 module_sizes: HashMap::new(),
622 compilation_times: HashMap::new(),
623 heavy_dependencies: HashSet::new(),
624 circular_dependencies: Vec::new(),
625 recommendations: Vec::new(),
626 };
627
628 analysis
629 .compilation_times
630 .insert("module1".to_string(), 5.0);
631 analysis
632 .compilation_times
633 .insert("module2".to_string(), 3.0);
634
635 analysis.recommendations.push(OptimizationRecommendation {
636 optimization_type: OptimizationType::ModuleRefactoring,
637 modules: vec!["module1".to_string()],
638 expected_improvement: 2.0,
639 description: "Test".to_string(),
640 priority: RecommendationPriority::Medium,
641 });
642
643 let efficiency = utils::get_efficiency_score(&analysis);
644 assert!(efficiency > 0.0 && efficiency <= 1.0);
645 }
646}