Skip to main content

cargo_mate/tools/
rust_mentor.rs

1use super::{Tool, Result, ToolError, common_options, parse_output_format, OutputFormat};
2use clap::{Arg, ArgMatches, Command};
3use colored::*;
4use std::fs;
5use std::path::Path;
6use std::collections::HashMap;
7use syn::{
8    parse_file, File, Item, ItemFn, ItemStruct, ItemTrait, Fields, Field, Type,
9    PathSegment, Ident, visit::Visit,
10};
11use quote::ToTokens;
12use serde::{Serialize, Deserialize};
13#[derive(Debug, Clone)]
14pub struct RustMentorTool;
15#[derive(Debug, Clone, Serialize, Deserialize)]
16struct CodeAnalysis {
17    functions: Vec<FunctionAnalysis>,
18    structs: Vec<StructAnalysis>,
19    traits: Vec<TraitAnalysis>,
20    patterns: Vec<PatternAnalysis>,
21    issues: Vec<CodeIssue>,
22    recommendations: Vec<Recommendation>,
23    learning_opportunities: Vec<LearningOpportunity>,
24}
25#[derive(Debug, Clone, Serialize, Deserialize)]
26struct FunctionAnalysis {
27    name: String,
28    complexity: u32,
29    parameters: Vec<ParameterInfo>,
30    return_type: Option<String>,
31    patterns_used: Vec<String>,
32    potential_improvements: Vec<String>,
33    explanation: String,
34}
35#[derive(Debug, Clone, Serialize, Deserialize)]
36struct StructAnalysis {
37    name: String,
38    fields: Vec<FieldInfo>,
39    patterns_used: Vec<String>,
40    design_considerations: Vec<String>,
41    explanation: String,
42}
43#[derive(Debug, Clone, Serialize, Deserialize)]
44struct TraitAnalysis {
45    name: String,
46    methods: Vec<String>,
47    purpose: String,
48    common_use_cases: Vec<String>,
49    explanation: String,
50}
51#[derive(Debug, Clone, Serialize, Deserialize)]
52struct PatternAnalysis {
53    pattern_type: String,
54    locations: Vec<String>,
55    explanation: String,
56    benefits: Vec<String>,
57    alternatives: Vec<String>,
58}
59#[derive(Debug, Clone, Serialize, Deserialize)]
60struct CodeIssue {
61    severity: String,
62    category: String,
63    location: String,
64    message: String,
65    explanation: String,
66    suggestion: String,
67}
68#[derive(Debug, Clone, Serialize, Deserialize)]
69struct Recommendation {
70    category: String,
71    priority: String,
72    title: String,
73    description: String,
74    code_example: Option<String>,
75    benefits: Vec<String>,
76}
77#[derive(Debug, Clone, Serialize, Deserialize)]
78struct LearningOpportunity {
79    topic: String,
80    current_level: String,
81    next_steps: Vec<String>,
82    resources: Vec<String>,
83    explanation: String,
84}
85#[derive(Debug, Clone, Serialize, Deserialize)]
86struct ParameterInfo {
87    name: String,
88    ty: String,
89    purpose: String,
90}
91#[derive(Debug, Clone, Serialize, Deserialize)]
92struct FieldInfo {
93    name: String,
94    ty: String,
95    purpose: String,
96    considerations: Vec<String>,
97}
98impl RustMentorTool {
99    pub fn new() -> Self {
100        Self
101    }
102    fn analyze_codebase(&self, input_path: &str) -> Result<CodeAnalysis> {
103        let mut functions = Vec::new();
104        let mut structs = Vec::new();
105        let mut traits = Vec::new();
106        if Path::new(input_path).is_dir() {
107            self.analyze_directory(
108                input_path,
109                &mut functions,
110                &mut structs,
111                &mut traits,
112            )?;
113        } else {
114            self.analyze_file(input_path, &mut functions, &mut structs, &mut traits)?;
115        }
116        let patterns = self.identify_patterns(&functions, &structs, &traits);
117        let issues = self.identify_issues(&functions, &structs, &traits);
118        let recommendations = self
119            .generate_recommendations(&functions, &structs, &traits, &issues);
120        let learning_opportunities = self
121            .identify_learning_opportunities(&functions, &structs, &traits);
122        Ok(CodeAnalysis {
123            functions,
124            structs,
125            traits,
126            patterns,
127            issues,
128            recommendations,
129            learning_opportunities,
130        })
131    }
132    fn analyze_directory(
133        &self,
134        dir_path: &str,
135        functions: &mut Vec<FunctionAnalysis>,
136        structs: &mut Vec<StructAnalysis>,
137        traits: &mut Vec<TraitAnalysis>,
138    ) -> Result<()> {
139        let entries = fs::read_dir(dir_path)
140            .map_err(|e| ToolError::ExecutionFailed(
141                format!("Failed to read directory {}: {}", dir_path, e),
142            ))?;
143        for entry in entries {
144            let entry = entry?;
145            let path = entry.path();
146            if path.is_dir() {
147                self.analyze_directory(
148                    &path.to_string_lossy(),
149                    functions,
150                    structs,
151                    traits,
152                )?;
153            } else if let Some(ext) = path.extension() {
154                if ext == "rs" && !path.ends_with("mod.rs") && !path.ends_with("lib.rs")
155                {
156                    self.analyze_file(
157                        &path.to_string_lossy(),
158                        functions,
159                        structs,
160                        traits,
161                    )?;
162                }
163            }
164        }
165        Ok(())
166    }
167    fn analyze_file(
168        &self,
169        file_path: &str,
170        functions: &mut Vec<FunctionAnalysis>,
171        structs: &mut Vec<StructAnalysis>,
172        traits: &mut Vec<TraitAnalysis>,
173    ) -> Result<()> {
174        let content = fs::read_to_string(file_path)?;
175        let ast = parse_file(&content)?;
176        struct CodeVisitor<'a> {
177            functions: &'a mut Vec<FunctionAnalysis>,
178            structs: &'a mut Vec<StructAnalysis>,
179            traits: &'a mut Vec<TraitAnalysis>,
180            current_file: String,
181        }
182        impl<'a> Visit<'_> for CodeVisitor<'a> {
183            fn visit_item_fn(&mut self, node: &ItemFn) {
184                if let Ok(analysis) = Self::analyze_function(node) {
185                    self.functions.push(analysis);
186                }
187            }
188            fn visit_item_struct(&mut self, node: &ItemStruct) {
189                if let Ok(analysis) = Self::analyze_struct(node) {
190                    self.structs.push(analysis);
191                }
192            }
193            fn visit_item_trait(&mut self, node: &ItemTrait) {
194                if let Ok(analysis) = Self::analyze_trait(node) {
195                    self.traits.push(analysis);
196                }
197            }
198        }
199        impl CodeVisitor<'_> {
200            fn analyze_function(node: &ItemFn) -> Result<FunctionAnalysis> {
201                let name = node.sig.ident.to_string();
202                let complexity = Self::calculate_complexity(node);
203                let parameters = Self::extract_parameters(&node.sig.inputs);
204                let return_type = Self::extract_return_type(&node.sig.output);
205                let patterns_used = Self::identify_function_patterns(node);
206                let potential_improvements = Self::suggest_function_improvements(node);
207                let explanation = Self::explain_function(node);
208                Ok(FunctionAnalysis {
209                    name,
210                    complexity,
211                    parameters,
212                    return_type,
213                    patterns_used,
214                    potential_improvements,
215                    explanation,
216                })
217            }
218            fn analyze_struct(node: &ItemStruct) -> Result<StructAnalysis> {
219                let name = node.ident.to_string();
220                let fields = Self::extract_fields(&node.fields);
221                let patterns_used = Self::identify_struct_patterns(node);
222                let design_considerations = Self::struct_design_considerations(node);
223                let explanation = Self::explain_struct(node);
224                Ok(StructAnalysis {
225                    name,
226                    fields,
227                    patterns_used,
228                    design_considerations,
229                    explanation,
230                })
231            }
232            fn analyze_trait(node: &ItemTrait) -> Result<TraitAnalysis> {
233                let name = node.ident.to_string();
234                let methods = Self::extract_trait_methods(node);
235                let purpose = Self::identify_trait_purpose(node);
236                let common_use_cases = Self::trait_use_cases(node);
237                let explanation = Self::explain_trait(node);
238                Ok(TraitAnalysis {
239                    name,
240                    methods,
241                    purpose,
242                    common_use_cases,
243                    explanation,
244                })
245            }
246            fn calculate_complexity(node: &ItemFn) -> u32 {
247                let mut complexity = 1u32;
248                let code = node.to_token_stream().to_string();
249                let control_flow_keywords = [
250                    "if",
251                    "else",
252                    "for",
253                    "while",
254                    "loop",
255                    "match",
256                ];
257                for keyword in &control_flow_keywords {
258                    complexity += code.matches(keyword).count() as u32;
259                }
260                complexity
261            }
262            fn extract_parameters(
263                inputs: &syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma>,
264            ) -> Vec<ParameterInfo> {
265                inputs
266                    .iter()
267                    .filter_map(|arg| {
268                        match arg {
269                            syn::FnArg::Receiver(_) => {
270                                Some(ParameterInfo {
271                                    name: "self".to_string(),
272                                    ty: "Self".to_string(),
273                                    purpose: "Reference to the current instance".to_string(),
274                                })
275                            }
276                            syn::FnArg::Typed(pat_type) => {
277                                if let syn::Pat::Ident(pat_ident) = &*pat_type.pat {
278                                    let name = pat_ident.ident.to_string();
279                                    let ty = Self::type_to_string(&*pat_type.ty);
280                                    let purpose = Self::infer_parameter_purpose(&name, &ty);
281                                    Some(ParameterInfo { name, ty, purpose })
282                                } else {
283                                    None
284                                }
285                            }
286                        }
287                    })
288                    .collect()
289            }
290            fn extract_return_type(output: &syn::ReturnType) -> Option<String> {
291                match output {
292                    syn::ReturnType::Default => None,
293                    syn::ReturnType::Type(_, ty) => Some(Self::type_to_string(ty)),
294                }
295            }
296            fn extract_fields(fields: &Fields) -> Vec<FieldInfo> {
297                match fields {
298                    Fields::Named(named_fields) => {
299                        named_fields
300                            .named
301                            .iter()
302                            .filter_map(|field| {
303                                field
304                                    .ident
305                                    .as_ref()
306                                    .map(|ident| {
307                                        let name = ident.to_string();
308                                        let ty = Self::type_to_string(&field.ty);
309                                        let purpose = Self::infer_field_purpose(&name, &ty);
310                                        let considerations = Self::field_considerations(&name, &ty);
311                                        FieldInfo {
312                                            name,
313                                            ty,
314                                            purpose,
315                                            considerations,
316                                        }
317                                    })
318                            })
319                            .collect()
320                    }
321                    _ => Vec::new(),
322                }
323            }
324            fn extract_trait_methods(node: &ItemTrait) -> Vec<String> {
325                node.items
326                    .iter()
327                    .filter_map(|item| {
328                        match item {
329                            syn::TraitItem::Fn(method) => {
330                                Some(method.sig.ident.to_string())
331                            }
332                            _ => None,
333                        }
334                    })
335                    .collect()
336            }
337            fn type_to_string(ty: &Type) -> String {
338                match ty {
339                    Type::Path(type_path) => {
340                        type_path
341                            .path
342                            .segments
343                            .iter()
344                            .map(|seg| seg.ident.to_string())
345                            .collect::<Vec<_>>()
346                            .join("::")
347                    }
348                    Type::Reference(type_ref) => {
349                        let mut result = "&".to_string();
350                        if type_ref.mutability.is_some() {
351                            result.push_str("mut ");
352                        }
353                        result.push_str(&Self::type_to_string(&*type_ref.elem));
354                        result
355                    }
356                    _ => "Unknown".to_string(),
357                }
358            }
359            fn identify_function_patterns(node: &ItemFn) -> Vec<String> {
360                let mut patterns = Vec::new();
361                let code = node.to_token_stream().to_string();
362                if code.contains("match") {
363                    patterns.push("Pattern Matching".to_string());
364                }
365                if code.contains("if let") {
366                    patterns.push("If-Let Pattern".to_string());
367                }
368                if code.contains("map") || code.contains("filter")
369                    || code.contains("fold")
370                {
371                    patterns.push("Iterator Methods".to_string());
372                }
373                if code.contains("?") {
374                    patterns.push("Error Propagation".to_string());
375                }
376                if node.sig.asyncness.is_some() {
377                    patterns.push("Async Function".to_string());
378                }
379                patterns
380            }
381            fn identify_struct_patterns(node: &ItemStruct) -> Vec<String> {
382                let mut patterns = Vec::new();
383                match &node.fields {
384                    Fields::Named(_) => patterns.push("Named Fields".to_string()),
385                    Fields::Unnamed(_) => patterns.push("Tuple Struct".to_string()),
386                    Fields::Unit => patterns.push("Unit Struct".to_string()),
387                }
388                let attrs = node
389                    .attrs
390                    .iter()
391                    .map(|attr| {
392                        attr.path()
393                            .segments
394                            .iter()
395                            .map(|seg| seg.ident.to_string())
396                            .collect::<Vec<_>>()
397                            .join("::")
398                    })
399                    .collect::<Vec<_>>();
400                if attrs.contains(&"derive".to_string()) {
401                    patterns.push("Derive Macros".to_string());
402                }
403                if attrs.contains(&"serde".to_string()) {
404                    patterns.push("Serialization Support".to_string());
405                }
406                patterns
407            }
408            fn infer_parameter_purpose(name: &str, ty: &str) -> String {
409                match (name, ty) {
410                    ("config" | "settings" | "options", _) => {
411                        "Configuration parameters".to_string()
412                    }
413                    ("data" | "input", _) => "Input data to process".to_string(),
414                    ("callback" | "handler", _) => "Function to call back".to_string(),
415                    (_, "String" | "&str") => "Text input or identifier".to_string(),
416                    (_, "i32" | "i64" | "u32" | "u64") => {
417                        "Numeric value or count".to_string()
418                    }
419                    (_, "&mut") => "Mutable reference for modification".to_string(),
420                    _ => format!("{} parameter of type {}", name, ty),
421                }
422            }
423            fn infer_field_purpose(name: &str, ty: &str) -> String {
424                match (name, ty) {
425                    ("id" | "uuid", _) => "Unique identifier".to_string(),
426                    ("name" | "title", _) => "Descriptive name or title".to_string(),
427                    ("config" | "settings", _) => "Configuration data".to_string(),
428                    ("data" | "content", _) => "Main content or data".to_string(),
429                    ("created_at" | "updated_at", _) => {
430                        "Timestamp information".to_string()
431                    }
432                    (_, "Vec<T>") => "Collection of items".to_string(),
433                    (_, "Option<T>") => "Optional value".to_string(),
434                    _ => format!("{} field of type {}", name, ty),
435                }
436            }
437            fn field_considerations(name: &str, ty: &str) -> Vec<String> {
438                let mut considerations = Vec::new();
439                if ty.contains("&str") && !ty.contains("String") {
440                    considerations
441                        .push("Consider using owned String for ownership".to_string());
442                }
443                if name.ends_with("_at") && ty.contains("u64") {
444                    considerations
445                        .push(
446                            "Consider using DateTime for better time handling"
447                                .to_string(),
448                        );
449                }
450                if name == "id" && ty == "String" {
451                    considerations
452                        .push(
453                            "Consider using UUID type for better type safety".to_string(),
454                        );
455                }
456                considerations
457            }
458            fn suggest_function_improvements(node: &ItemFn) -> Vec<String> {
459                let mut improvements = Vec::new();
460                let code = node.to_token_stream().to_string();
461                if node.sig.inputs.len() > 4 {
462                    improvements
463                        .push(
464                            "Consider grouping parameters into a configuration struct"
465                                .to_string(),
466                        );
467                }
468                if code.len() > 1000 {
469                    improvements
470                        .push(
471                            "Function is quite long - consider breaking into smaller functions"
472                                .to_string(),
473                        );
474                }
475                if !code.contains("Result") && !code.contains("Option") {
476                    improvements
477                        .push(
478                            "Consider adding error handling for robustness".to_string(),
479                        );
480                }
481                improvements
482            }
483            fn struct_design_considerations(node: &ItemStruct) -> Vec<String> {
484                let mut considerations = Vec::new();
485                match &node.fields {
486                    Fields::Named(named_fields) if named_fields.named.len() > 10 => {
487                        considerations
488                            .push(
489                                "Large struct - consider splitting into smaller structs"
490                                    .to_string(),
491                            );
492                    }
493                    Fields::Unnamed(
494                        unnamed_fields,
495                    ) if unnamed_fields.unnamed.len() > 5 => {
496                        considerations
497                            .push(
498                                "Many tuple fields - consider using named fields for clarity"
499                                    .to_string(),
500                            );
501                    }
502                    _ => {}
503                }
504                considerations
505            }
506            fn identify_trait_purpose(node: &ItemTrait) -> String {
507                let name = node.ident.to_string();
508                let method_count = node.items.len();
509                match (name.as_str(), method_count) {
510                    ("Debug", _) => "Enable debug printing and inspection".to_string(),
511                    ("Clone", _) => "Allow creating copies of values".to_string(),
512                    ("Display", _) => {
513                        "Enable user-friendly string representation".to_string()
514                    }
515                    ("From" | "Into", _) => "Enable type conversions".to_string(),
516                    ("Iterator", _) => "Enable iteration over collections".to_string(),
517                    (_, 1) => {
518                        "Single method interface - likely a callback or conversion trait"
519                            .to_string()
520                    }
521                    (_, 2..=3) => {
522                        "Small interface - focused on specific functionality".to_string()
523                    }
524                    _ => {
525                        "Larger interface - represents a capability or behavior"
526                            .to_string()
527                    }
528                }
529            }
530            fn trait_use_cases(node: &ItemTrait) -> Vec<String> {
531                let name = node.ident.to_string();
532                match name.as_str() {
533                    "Debug" => {
534                        vec![
535                            "Debugging and logging".to_string(), "Error messages"
536                            .to_string()
537                        ]
538                    }
539                    "Clone" => {
540                        vec![
541                            "Creating copies of data".to_string(),
542                            "Working with collections".to_string()
543                        ]
544                    }
545                    "Display" => {
546                        vec![
547                            "User-facing output".to_string(), "Logging and reporting"
548                            .to_string()
549                        ]
550                    }
551                    "From" | "Into" => {
552                        vec![
553                            "Type conversions".to_string(), "Builder patterns"
554                            .to_string()
555                        ]
556                    }
557                    "Iterator" => {
558                        vec![
559                            "Working with collections".to_string(), "Streaming data"
560                            .to_string()
561                        ]
562                    }
563                    _ => vec!["Domain-specific functionality".to_string()],
564                }
565            }
566            fn explain_function(node: &ItemFn) -> String {
567                let name = node.sig.ident.to_string();
568                let param_count = node.sig.inputs.len();
569                let has_return = !matches!(node.sig.output, syn::ReturnType::Default);
570                let is_async = node.sig.asyncness.is_some();
571                let mut explanation = format!("Function `{}` ", name);
572                if is_async {
573                    explanation.push_str("is an asynchronous function that ");
574                } else {
575                    explanation.push_str("is a synchronous function that ");
576                }
577                if has_return {
578                    explanation.push_str("takes ");
579                } else {
580                    explanation.push_str("performs an operation");
581                }
582                match param_count {
583                    0 => explanation.push_str("no parameters and "),
584                    1 => explanation.push_str("one parameter and "),
585                    2..=3 => {
586                        explanation.push_str(&format!("{} parameters and ", param_count))
587                    }
588                    _ => {
589                        explanation.push_str(&format!("{} parameters and ", param_count))
590                    }
591                }
592                if has_return {
593                    explanation.push_str("returns a value");
594                } else {
595                    explanation.push_str("doesn't return a value");
596                }
597                explanation.push_str(". ");
598                if node
599                    .sig
600                    .inputs
601                    .iter()
602                    .any(|arg| matches!(arg, syn::FnArg::Receiver(_)))
603                {
604                    explanation
605                        .push_str("It operates on an instance of its type (method). ");
606                } else {
607                    explanation.push_str("It operates as a standalone function. ");
608                }
609                explanation
610            }
611            fn explain_struct(node: &ItemStruct) -> String {
612                let name = node.ident.to_string();
613                match &node.fields {
614                    Fields::Named(named_fields) => {
615                        let field_count = named_fields.named.len();
616                        format!(
617                            "Struct `{}` has {} named fields, representing a data structure with clear field names for better code readability and maintainability.",
618                            name, field_count
619                        )
620                    }
621                    Fields::Unnamed(unnamed_fields) => {
622                        let field_count = unnamed_fields.unnamed.len();
623                        format!(
624                            "Struct `{}` is a tuple struct with {} unnamed fields, useful for simple data aggregation where field names aren't needed.",
625                            name, field_count
626                        )
627                    }
628                    Fields::Unit => {
629                        format!(
630                            "Struct `{}` is a unit struct with no fields, often used as a marker type or for implementing traits.",
631                            name
632                        )
633                    }
634                }
635            }
636            fn explain_trait(node: &ItemTrait) -> String {
637                let name = node.ident.to_string();
638                let method_count = node.items.len();
639                format!(
640                    "Trait `{}` defines an interface with {} methods that types can implement to provide specific functionality. It represents a capability that implementing types must provide.",
641                    name, method_count
642                )
643            }
644        }
645        let mut visitor = CodeVisitor {
646            functions,
647            structs,
648            traits,
649            current_file: file_path.to_string(),
650        };
651        syn::visit::visit_file(&mut visitor, &ast);
652        Ok(())
653    }
654    fn identify_patterns(
655        &self,
656        functions: &[FunctionAnalysis],
657        structs: &[StructAnalysis],
658        traits: &[TraitAnalysis],
659    ) -> Vec<PatternAnalysis> {
660        let mut patterns = Vec::new();
661        let mut pattern_usage = HashMap::new();
662        for func in functions {
663            for pattern in &func.patterns_used {
664                let count = pattern_usage.entry(pattern.clone()).or_insert(0);
665                *count += 1;
666            }
667        }
668        for (pattern, count) in pattern_usage {
669            if count > 0 {
670                patterns
671                    .push(PatternAnalysis {
672                        pattern_type: pattern.clone(),
673                        locations: vec![format!("Found in {} functions", count)],
674                        explanation: self.explain_pattern(&pattern),
675                        benefits: self.pattern_benefits(&pattern),
676                        alternatives: self.pattern_alternatives(&pattern),
677                    });
678            }
679        }
680        patterns
681    }
682    fn identify_issues(
683        &self,
684        functions: &[FunctionAnalysis],
685        structs: &[StructAnalysis],
686        traits: &[TraitAnalysis],
687    ) -> Vec<CodeIssue> {
688        let mut issues = Vec::new();
689        for func in functions {
690            if func.complexity > 10 {
691                issues
692                    .push(CodeIssue {
693                        severity: "warning".to_string(),
694                        category: "complexity".to_string(),
695                        location: func.name.clone(),
696                        message: format!(
697                            "High complexity function (score: {})", func.complexity
698                        ),
699                        explanation: "Functions with high complexity are harder to understand and maintain"
700                            .to_string(),
701                        suggestion: "Consider breaking into smaller functions or simplifying logic"
702                            .to_string(),
703                    });
704            }
705        }
706        for struct_info in structs {
707            if struct_info.fields.len() > 15 {
708                issues
709                    .push(CodeIssue {
710                        severity: "info".to_string(),
711                        category: "design".to_string(),
712                        location: struct_info.name.clone(),
713                        message: format!(
714                            "Large struct with {} fields", struct_info.fields.len()
715                        ),
716                        explanation: "Large structs can be difficult to work with and may indicate a need for better organization"
717                            .to_string(),
718                        suggestion: "Consider splitting into smaller, more focused structs"
719                            .to_string(),
720                    });
721            }
722        }
723        issues
724    }
725    fn generate_recommendations(
726        &self,
727        functions: &[FunctionAnalysis],
728        structs: &[StructAnalysis],
729        traits: &[TraitAnalysis],
730        issues: &[CodeIssue],
731    ) -> Vec<Recommendation> {
732        let mut recommendations = Vec::new();
733        for issue in issues {
734            recommendations
735                .push(Recommendation {
736                    category: issue.category.clone(),
737                    priority: match issue.severity.as_str() {
738                        "error" => "high".to_string(),
739                        "warning" => "medium".to_string(),
740                        _ => "low".to_string(),
741                    },
742                    title: format!("Address {}", issue.category),
743                    description: issue.explanation.clone(),
744                    code_example: None,
745                    benefits: vec![
746                        "Improved code maintainability".to_string(),
747                        "Better developer experience".to_string(),
748                        "Reduced bug likelihood".to_string(),
749                    ],
750                });
751        }
752        if functions
753            .iter()
754            .any(|f| f.patterns_used.contains(&"Error Propagation".to_string()))
755        {
756            recommendations
757                .push(Recommendation {
758                    category: "error_handling".to_string(),
759                    priority: "medium".to_string(),
760                    title: "Consider using thiserror for better error handling"
761                        .to_string(),
762                    description: "Using thiserror provides better error messages and easier error handling"
763                        .to_string(),
764                    code_example: Some(
765                        "#[derive(thiserror::Error, Debug)]\npub enum AppError {\n    #[error(\"IO error: {0}\")]\n    Io(#[from] std::io::Error),\n    #[error(\"Parse error: {0}\")]\n    Parse(String),\n}"
766                            .to_string(),
767                    ),
768                    benefits: vec![
769                        "Better error messages".to_string(), "Easier error handling"
770                        .to_string(), "Consistent error types".to_string(),
771                    ],
772                });
773        }
774        if structs
775            .iter()
776            .any(|s| s.patterns_used.contains(&"Serialization Support".to_string()))
777        {
778            recommendations
779                .push(Recommendation {
780                    category: "serialization".to_string(),
781                    priority: "low".to_string(),
782                    title: "Consider adding validation for serialized data".to_string(),
783                    description: "Adding validation ensures data integrity when serializing/deserializing"
784                        .to_string(),
785                    code_example: Some(
786                        "#[derive(serde::Deserialize, validator::Validate)]\npub struct User {\n    #[validate(length(min = 1, max = 100))]\n    pub name: String,\n    #[validate(email)]\n    pub email: String,\n}"
787                            .to_string(),
788                    ),
789                    benefits: vec![
790                        "Data integrity".to_string(), "Better error messages"
791                        .to_string(), "Security improvements".to_string(),
792                    ],
793                });
794        }
795        recommendations
796    }
797    fn identify_learning_opportunities(
798        &self,
799        functions: &[FunctionAnalysis],
800        structs: &[StructAnalysis],
801        traits: &[TraitAnalysis],
802    ) -> Vec<LearningOpportunity> {
803        let mut opportunities = Vec::new();
804        let async_functions = functions
805            .iter()
806            .filter(|f| f.patterns_used.contains(&"Async Function".to_string()))
807            .count();
808        if async_functions == 0 {
809            opportunities
810                .push(LearningOpportunity {
811                    topic: "Asynchronous Programming".to_string(),
812                    current_level: "Beginner".to_string(),
813                    next_steps: vec![
814                        "Learn async/await syntax".to_string(),
815                        "Understand futures and promises".to_string(),
816                        "Practice with tokio runtime".to_string(),
817                    ],
818                    resources: vec![
819                        "https://rust-lang.github.io/async-book/".to_string(),
820                        "https://tokio.rs/".to_string(),
821                    ],
822                    explanation: "Async programming is becoming increasingly important in Rust for building scalable applications"
823                        .to_string(),
824                });
825        }
826        let error_handling = functions
827            .iter()
828            .filter(|f| f.patterns_used.contains(&"Error Propagation".to_string()))
829            .count();
830        if error_handling == 0 {
831            opportunities
832                .push(LearningOpportunity {
833                    topic: "Error Handling".to_string(),
834                    current_level: "Beginner".to_string(),
835                    next_steps: vec![
836                        "Learn Result and Option types".to_string(),
837                        "Use ? operator for error propagation".to_string(),
838                        "Create custom error types".to_string(),
839                        "Use thiserror for better errors".to_string(),
840                    ],
841                    resources: vec![
842                        "https://doc.rust-lang.org/book/ch09-00-error-handling.html"
843                        .to_string(), "https://docs.rs/thiserror/latest/thiserror/"
844                        .to_string(),
845                    ],
846                    explanation: "Proper error handling is crucial for robust Rust applications"
847                        .to_string(),
848                });
849        }
850        let iterator_usage = functions
851            .iter()
852            .filter(|f| f.patterns_used.contains(&"Iterator Methods".to_string()))
853            .count();
854        if iterator_usage == 0 {
855            opportunities
856                .push(LearningOpportunity {
857                    topic: "Iterator Patterns".to_string(),
858                    current_level: "Beginner".to_string(),
859                    next_steps: vec![
860                        "Learn map, filter, fold methods".to_string(),
861                        "Understand iterator chains".to_string(),
862                        "Create custom iterators".to_string(),
863                    ],
864                    resources: vec![
865                        "https://doc.rust-lang.org/book/ch13-02-iterators.html"
866                        .to_string(),
867                    ],
868                    explanation: "Iterators provide powerful and efficient ways to work with collections"
869                        .to_string(),
870                });
871        }
872        opportunities
873    }
874    fn explain_pattern(&self, pattern: &str) -> String {
875        match pattern {
876            "Pattern Matching" => {
877                "Pattern matching allows you to destructure and match values against patterns, providing a powerful way to handle different cases in your code."
878                    .to_string()
879            }
880            "If-Let Pattern" => {
881                "If-let is a concise way to handle optional values and single-case matches, reducing boilerplate compared to full match statements."
882                    .to_string()
883            }
884            "Iterator Methods" => {
885                "Iterator methods like map, filter, and fold provide functional programming patterns that make data transformation more concise and readable."
886                    .to_string()
887            }
888            "Error Propagation" => {
889                "The ? operator provides concise error propagation, automatically converting errors to the expected return type."
890                    .to_string()
891            }
892            "Async Function" => {
893                "Async functions allow you to write asynchronous code that looks like synchronous code, making concurrent programming more accessible."
894                    .to_string()
895            }
896            _ => format!("{} is a code pattern used in this codebase.", pattern),
897        }
898    }
899    fn pattern_benefits(&self, pattern: &str) -> Vec<String> {
900        match pattern {
901            "Pattern Matching" => {
902                vec![
903                    "Exhaustive checking prevents bugs".to_string(),
904                    "Clear expression of intent".to_string(),
905                    "Powerful destructuring capabilities".to_string(),
906                ]
907            }
908            "Iterator Methods" => {
909                vec![
910                    "More concise and readable code".to_string(), "Composable operations"
911                    .to_string(), "Lazy evaluation for performance".to_string(),
912                ]
913            }
914            "Error Propagation" => {
915                vec![
916                    "Reduces boilerplate error handling".to_string(),
917                    "Makes error paths more visible".to_string(),
918                    "Enforces error handling".to_string(),
919                ]
920            }
921            _ => vec!["Improves code quality".to_string()],
922        }
923    }
924    fn pattern_alternatives(&self, pattern: &str) -> Vec<String> {
925        match pattern {
926            "Pattern Matching" => {
927                vec!["If-else chains".to_string(), "Method dispatch".to_string(),]
928            }
929            "Iterator Methods" => {
930                vec![
931                    "Traditional loops".to_string(), "Manual collection building"
932                    .to_string(),
933                ]
934            }
935            "Error Propagation" => {
936                vec![
937                    "Manual match statements".to_string(), "Panic on error".to_string(),
938                ]
939            }
940            _ => vec!["Alternative approaches available".to_string()],
941        }
942    }
943}
944impl Tool for RustMentorTool {
945    fn name(&self) -> &'static str {
946        "rust-mentor"
947    }
948    fn description(&self) -> &'static str {
949        "Interactive learning and guidance system for Rust developers"
950    }
951    fn command(&self) -> Command {
952        Command::new(self.name())
953            .about(self.description())
954            .long_about(
955                "An interactive learning and guidance system that analyzes your Rust code and provides personalized explanations, best practice suggestions, and learning recommendations. Perfect for developers at all levels looking to improve their Rust skills.",
956            )
957            .args(
958                &[
959                    Arg::new("input")
960                        .long("input")
961                        .short('i')
962                        .help("Input Rust file or directory to analyze")
963                        .required(true),
964                    Arg::new("explain")
965                        .long("explain")
966                        .short('e')
967                        .help("Explain what specific code constructs do"),
968                    Arg::new("suggest")
969                        .long("suggest")
970                        .help("Show improvement suggestions")
971                        .action(clap::ArgAction::SetTrue),
972                    Arg::new("learn")
973                        .long("learn")
974                        .help("Show learning opportunities")
975                        .action(clap::ArgAction::SetTrue),
976                    Arg::new("patterns")
977                        .long("patterns")
978                        .help("Analyze code patterns used")
979                        .action(clap::ArgAction::SetTrue),
980                    Arg::new("focus")
981                        .long("focus")
982                        .short('f')
983                        .help("Focus on specific aspects (functions, structs, traits)")
984                        .default_value("all"),
985                    Arg::new("level")
986                        .long("level")
987                        .help("Experience level (beginner, intermediate, advanced)")
988                        .default_value("intermediate"),
989                    Arg::new("detailed")
990                        .long("detailed")
991                        .short('d')
992                        .help("Show detailed explanations")
993                        .action(clap::ArgAction::SetTrue),
994                ],
995            )
996            .args(&common_options())
997    }
998    fn execute(&self, matches: &ArgMatches) -> Result<()> {
999        let input = matches.get_one::<String>("input").unwrap();
1000        let explain_target = matches.get_one::<String>("explain");
1001        let suggest = matches.get_flag("suggest");
1002        let learn = matches.get_flag("learn");
1003        let patterns = matches.get_flag("patterns");
1004        let focus = matches.get_one::<String>("focus").unwrap();
1005        let level = matches.get_one::<String>("level").unwrap();
1006        let detailed = matches.get_flag("detailed");
1007        let dry_run = matches.get_flag("dry-run");
1008        let verbose = matches.get_flag("verbose");
1009        let output_format = parse_output_format(matches);
1010        println!(
1011            "šŸŽ“ {} - {}", "CargoMate RustMentor".bold().blue(), self.description()
1012            .cyan()
1013        );
1014        if !Path::new(input).exists() {
1015            return Err(
1016                ToolError::InvalidArguments(format!("Input not found: {}", input)),
1017            );
1018        }
1019        if verbose {
1020            println!("   šŸ“š Analyzing codebase for learning opportunities...");
1021        }
1022        let analysis = self.analyze_codebase(input)?;
1023        if verbose {
1024            println!(
1025                "   šŸ“Š Found {} functions, {} structs, {} traits", analysis.functions
1026                .len(), analysis.structs.len(), analysis.traits.len()
1027            );
1028            println!(
1029                "   šŸ” Identified {} patterns, {} issues, {} recommendations", analysis
1030                .patterns.len(), analysis.issues.len(), analysis.recommendations.len()
1031            );
1032        }
1033        match output_format {
1034            OutputFormat::Human => {
1035                self.display_human_analysis(
1036                    &analysis,
1037                    explain_target,
1038                    suggest,
1039                    learn,
1040                    patterns,
1041                    focus,
1042                    level,
1043                    detailed,
1044                );
1045            }
1046            OutputFormat::Json => {
1047                let json_analysis = serde_json::to_string_pretty(&analysis)?;
1048                println!("{}", json_analysis);
1049            }
1050            OutputFormat::Table => {
1051                self.display_table_analysis(&analysis);
1052            }
1053        }
1054        println!(
1055            "\nšŸŽ‰ Learning analysis complete! Use the insights above to improve your Rust skills."
1056        );
1057        Ok(())
1058    }
1059}
1060impl RustMentorTool {
1061    fn display_human_analysis(
1062        &self,
1063        analysis: &CodeAnalysis,
1064        explain_target: Option<&String>,
1065        suggest: bool,
1066        learn: bool,
1067        patterns: bool,
1068        focus: &str,
1069        level: &str,
1070        detailed: bool,
1071    ) {
1072        println!("\n🧠 {}", "Rust Learning Analysis".bold().underline());
1073        println!("\nšŸ“Š {}", "Codebase Overview".bold());
1074        println!("   Functions: {}", analysis.functions.len());
1075        println!("   Structs: {}", analysis.structs.len());
1076        println!("   Traits: {}", analysis.traits.len());
1077        println!("   Code Issues: {}", analysis.issues.len());
1078        println!("   Recommendations: {}", analysis.recommendations.len());
1079        println!("   Learning Opportunities: {}", analysis.learning_opportunities.len());
1080        match focus {
1081            "functions" => self.display_functions(&analysis.functions, detailed),
1082            "structs" => self.display_structs(&analysis.structs, detailed),
1083            "traits" => self.display_traits(&analysis.traits, detailed),
1084            _ => {
1085                self.display_functions(&analysis.functions, detailed);
1086                self.display_structs(&analysis.structs, detailed);
1087                self.display_traits(&analysis.traits, detailed);
1088            }
1089        }
1090        if let Some(target) = explain_target {
1091            self.explain_specific_target(analysis, target);
1092        }
1093        if patterns {
1094            self.display_patterns(&analysis.patterns);
1095        }
1096        if suggest {
1097            self.display_recommendations(&analysis.recommendations);
1098        }
1099        if learn {
1100            self.display_learning_opportunities(&analysis.learning_opportunities, level);
1101        }
1102        if !analysis.issues.is_empty() {
1103            self.display_issues(&analysis.issues);
1104        }
1105    }
1106    fn display_functions(&self, functions: &[FunctionAnalysis], detailed: bool) {
1107        if functions.is_empty() {
1108            return;
1109        }
1110        println!("\nšŸ“ {}", "Function Analysis".bold());
1111        for func in functions {
1112            println!("   šŸ”¹ {}", func.name.bold());
1113            println!("      {}", func.explanation);
1114            if detailed {
1115                if func.complexity > 1 {
1116                    println!(
1117                        "      Complexity: {} (higher = more complex)", func.complexity
1118                    );
1119                }
1120                if !func.patterns_used.is_empty() {
1121                    println!("      Patterns: {}", func.patterns_used.join(", "));
1122                }
1123                if !func.potential_improvements.is_empty() {
1124                    println!("      šŸ’” Suggestions:");
1125                    for suggestion in &func.potential_improvements {
1126                        println!("         • {}", suggestion);
1127                    }
1128                }
1129            }
1130            println!();
1131        }
1132    }
1133    fn display_structs(&self, structs: &[StructAnalysis], detailed: bool) {
1134        if structs.is_empty() {
1135            return;
1136        }
1137        println!("\nšŸ—ļø  {}", "Struct Analysis".bold());
1138        for struct_info in structs {
1139            println!("   šŸ›ļø  {}", struct_info.name.bold());
1140            println!("      {}", struct_info.explanation);
1141            if detailed {
1142                if !struct_info.patterns_used.is_empty() {
1143                    println!("      Patterns: {}", struct_info.patterns_used.join(", "));
1144                }
1145                if !struct_info.design_considerations.is_empty() {
1146                    println!("      šŸ’” Design Notes:");
1147                    for consideration in &struct_info.design_considerations {
1148                        println!("         • {}", consideration);
1149                    }
1150                }
1151            }
1152            println!();
1153        }
1154    }
1155    fn display_traits(&self, traits: &[TraitAnalysis], detailed: bool) {
1156        if traits.is_empty() {
1157            return;
1158        }
1159        println!("\nšŸŽ­ {}", "Trait Analysis".bold());
1160        for trait_info in traits {
1161            println!("   šŸŽŖ {}", trait_info.name.bold());
1162            println!("      {}", trait_info.explanation);
1163            println!("      Purpose: {}", trait_info.purpose);
1164            if detailed {
1165                if !trait_info.methods.is_empty() {
1166                    println!("      Methods: {}", trait_info.methods.join(", "));
1167                }
1168                if !trait_info.common_use_cases.is_empty() {
1169                    println!(
1170                        "      Use Cases: {}", trait_info.common_use_cases.join(", ")
1171                    );
1172                }
1173            }
1174            println!();
1175        }
1176    }
1177    fn explain_specific_target(&self, analysis: &CodeAnalysis, target: &str) {
1178        println!("\nšŸ” {}", format!("Deep Dive: {}", target) .bold());
1179        for func in &analysis.functions {
1180            if func.name == target {
1181                println!("   Type: Function");
1182                println!("   {}", func.explanation);
1183                if !func.patterns_used.is_empty() {
1184                    println!("   Patterns Used: {}", func.patterns_used.join(", "));
1185                }
1186                return;
1187            }
1188        }
1189        for struct_info in &analysis.structs {
1190            if struct_info.name == target {
1191                println!("   Type: Struct");
1192                println!("   {}", struct_info.explanation);
1193                if !struct_info.patterns_used.is_empty() {
1194                    println!(
1195                        "   Patterns Used: {}", struct_info.patterns_used.join(", ")
1196                    );
1197                }
1198                return;
1199            }
1200        }
1201        for trait_info in &analysis.traits {
1202            if trait_info.name == target {
1203                println!("   Type: Trait");
1204                println!("   {}", trait_info.explanation);
1205                println!("   Purpose: {}", trait_info.purpose);
1206                return;
1207            }
1208        }
1209        println!("   āŒ Target '{}' not found in the analyzed code.", target);
1210    }
1211    fn display_patterns(&self, patterns: &[PatternAnalysis]) {
1212        if patterns.is_empty() {
1213            return;
1214        }
1215        println!("\nšŸŽØ {}", "Code Patterns Used".bold());
1216        for pattern in patterns {
1217            println!("   šŸŽ­ {}", pattern.pattern_type.bold());
1218            println!("      {}", pattern.explanation);
1219            println!("      Benefits: {}", pattern.benefits.join(", "));
1220            if !pattern.alternatives.is_empty() {
1221                println!("      Alternatives: {}", pattern.alternatives.join(", "));
1222            }
1223            println!();
1224        }
1225    }
1226    fn display_recommendations(&self, recommendations: &[Recommendation]) {
1227        if recommendations.is_empty() {
1228            return;
1229        }
1230        println!("\nšŸ’” {}", "Recommendations".bold());
1231        for recommendation in recommendations {
1232            let priority_icon = match recommendation.priority.as_str() {
1233                "high" => "šŸ”“",
1234                "medium" => "🟔",
1235                "low" => "🟢",
1236                _ => "⚪",
1237            };
1238            println!("   {} {}", priority_icon, recommendation.title.bold());
1239            println!("      {}", recommendation.description);
1240            if let Some(code) = &recommendation.code_example {
1241                println!("      ```rust");
1242                for line in code.lines() {
1243                    println!("      {}", line);
1244                }
1245                println!("      ```");
1246            }
1247            if !recommendation.benefits.is_empty() {
1248                println!("      Benefits: {}", recommendation.benefits.join(", "));
1249            }
1250            println!();
1251        }
1252    }
1253    fn display_learning_opportunities(
1254        &self,
1255        opportunities: &[LearningOpportunity],
1256        level: &str,
1257    ) {
1258        if opportunities.is_empty() {
1259            return;
1260        }
1261        println!("\nšŸŽ“ {}", "Learning Opportunities".bold());
1262        println!("   Tailored for {} Rust developers:", level);
1263        for opportunity in opportunities {
1264            println!("   šŸ“š {}", opportunity.topic.bold());
1265            println!("      {}", opportunity.explanation);
1266            println!("      Current Level: {}", opportunity.current_level);
1267            if !opportunity.next_steps.is_empty() {
1268                println!("      Next Steps:");
1269                for step in &opportunity.next_steps {
1270                    println!("         • {}", step);
1271                }
1272            }
1273            if !opportunity.resources.is_empty() {
1274                println!("      Resources:");
1275                for resource in &opportunity.resources {
1276                    println!("         • {}", resource.cyan());
1277                }
1278            }
1279            println!();
1280        }
1281    }
1282    fn display_issues(&self, issues: &[CodeIssue]) {
1283        println!("\nāš ļø  {}", "Code Issues Found".bold());
1284        for issue in issues {
1285            let severity_icon = match issue.severity.as_str() {
1286                "error" => "āŒ",
1287                "warning" => "āš ļø ",
1288                "info" => "ā„¹ļø ",
1289                _ => "•",
1290            };
1291            println!("   {} {}", severity_icon, issue.message.bold());
1292            println!("      Location: {}", issue.location);
1293            println!("      {}", issue.explanation);
1294            println!("      šŸ’” {}", issue.suggestion);
1295            println!();
1296        }
1297    }
1298    fn display_table_analysis(&self, analysis: &CodeAnalysis) {
1299        println!(
1300            "{:<20} {:<10} {:<10} {:<10} {:<10}", "Category", "Count", "Patterns",
1301            "Issues", "Learning"
1302        );
1303        println!("{}", "─".repeat(70));
1304        println!(
1305            "{:<20} {:<10} {:<10} {:<10} {:<10}", "Functions", analysis.functions.len(),
1306            "-", "-", "-"
1307        );
1308        println!(
1309            "{:<20} {:<10} {:<10} {:<10} {:<10}", "Structs", analysis.structs.len(), "-",
1310            "-", "-"
1311        );
1312        println!(
1313            "{:<20} {:<10} {:<10} {:<10} {:<10}", "Traits", analysis.traits.len(), "-",
1314            "-", "-"
1315        );
1316        println!(
1317            "{:<20} {:<10} {:<10} {:<10} {:<10}", "Code Patterns", "-", analysis.patterns
1318            .len(), "-", "-"
1319        );
1320        println!(
1321            "{:<20} {:<10} {:<10} {:<10} {:<10}", "Issues", "-", "-", analysis.issues
1322            .len(), "-"
1323        );
1324        println!(
1325            "{:<20} {:<10} {:<10} {:<10} {:<10}", "Recommendations", "-", "-", "-",
1326            analysis.recommendations.len()
1327        );
1328        println!(
1329            "{:<20} {:<10} {:<10} {:<10} {:<10}", "Learning Ops", "-", "-", "-", analysis
1330            .learning_opportunities.len()
1331        );
1332    }
1333}
1334impl Default for RustMentorTool {
1335    fn default() -> Self {
1336        Self::new()
1337    }
1338}