Skip to main content

ryo_executor/executor/registry/converters/
trait_.rs

1//! TraitConverter: Converts trait abstraction MutationSpecs to Mutations
2//!
3//! Handles 3 trait transformation variants:
4//! - ExtractTrait: Extract a trait from an impl block
5//! - InlineTrait: Inline a trait back into inherent impl
6//! - EnumToTrait: Convert enum to trait + struct implementations
7
8use crate::engine::ASTRegApply;
9use crate::executor::registry::converter::{ConvertError, MutationConverter};
10use crate::executor::registry::converters::ResolveTargetSymbol;
11use crate::executor::spec::MutationSpec;
12use ryo_analysis::AnalysisContext;
13use ryo_mutations::{EnumToTraitMutation, ExtractTraitMutation, InlineTraitMutation};
14
15/// Converter for trait abstraction MutationSpecs
16pub struct TraitConverter;
17
18impl TraitConverter {
19    pub fn new() -> Self {
20        Self
21    }
22}
23
24impl Default for TraitConverter {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30// TraitConverter uses the default implementation of ResolveTargetSymbol
31impl ResolveTargetSymbol for TraitConverter {}
32
33impl MutationConverter for TraitConverter {
34    fn spec_kinds(&self) -> &'static [&'static str] {
35        &["ExtractTrait", "InlineTrait", "EnumToTrait"]
36    }
37
38    fn convert_v2(
39        &self,
40        spec: &MutationSpec,
41        ctx: &AnalysisContext,
42    ) -> Result<Vec<Box<dyn ASTRegApply>>, ConvertError> {
43        match spec {
44            MutationSpec::ExtractTrait {
45                target: target_symbol,
46                trait_name,
47                methods,
48            } => {
49                // Resolve target_symbol to SymbolId
50                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;
51                let mut mutation = ExtractTraitMutation::new(symbol_id, trait_name);
52                if let Some(m) = methods {
53                    mutation = mutation.with_methods(m.clone());
54                }
55                Ok(vec![Box::new(mutation)])
56            }
57
58            MutationSpec::InlineTrait {
59                target: target_symbol,
60                struct_name,
61                remove_trait,
62            } => {
63                // Resolve target_symbol to SymbolId
64                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;
65                let mut mutation = InlineTraitMutation::new(symbol_id, struct_name);
66                if !remove_trait {
67                    mutation = mutation.keep_trait();
68                }
69                Ok(vec![Box::new(mutation)])
70            }
71
72            MutationSpec::EnumToTrait {
73                target: target_symbol,
74                trait_name,
75                remove_enum,
76                strategy,
77                match_handling,
78            } => {
79                // Resolve target_symbol to SymbolId
80                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;
81
82                let mut mutation = EnumToTraitMutation::from_symbol_id(symbol_id)
83                    .with_strategy(*strategy)
84                    .with_match_handling(*match_handling);
85                if let Some(t_name) = trait_name {
86                    mutation = mutation.with_trait_name(t_name);
87                }
88                if !remove_enum {
89                    mutation = mutation.keep_enum();
90                }
91                Ok(vec![Box::new(mutation)])
92            }
93
94            _ => Err(ConvertError::TypeMismatch {
95                expected: "ExtractTrait, InlineTrait, or EnumToTrait",
96                actual: spec.kind_name().to_string(),
97            }),
98        }
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn test_trait_converter_spec_kinds() {
108        let converter = TraitConverter::new();
109        assert_eq!(
110            converter.spec_kinds(),
111            &["ExtractTrait", "InlineTrait", "EnumToTrait"]
112        );
113    }
114}