ryo-executor 0.1.0

[experimental] Mutation execution engine for RYO - parallel execution, conflict detection, workspace management
Documentation
//! TraitConverter: Converts trait abstraction MutationSpecs to Mutations
//!
//! Handles 3 trait transformation variants:
//! - ExtractTrait: Extract a trait from an impl block
//! - InlineTrait: Inline a trait back into inherent impl
//! - EnumToTrait: Convert enum to trait + struct implementations

use crate::engine::ASTRegApply;
use crate::executor::registry::converter::{ConvertError, MutationConverter};
use crate::executor::registry::converters::ResolveTargetSymbol;
use crate::executor::spec::MutationSpec;
use ryo_analysis::AnalysisContext;
use ryo_mutations::{EnumToTraitMutation, ExtractTraitMutation, InlineTraitMutation};

/// Converter for trait abstraction MutationSpecs
pub struct TraitConverter;

impl TraitConverter {
    pub fn new() -> Self {
        Self
    }
}

impl Default for TraitConverter {
    fn default() -> Self {
        Self::new()
    }
}

// TraitConverter uses the default implementation of ResolveTargetSymbol
impl ResolveTargetSymbol for TraitConverter {}

impl MutationConverter for TraitConverter {
    fn spec_kinds(&self) -> &'static [&'static str] {
        &["ExtractTrait", "InlineTrait", "EnumToTrait"]
    }

    fn convert_v2(
        &self,
        spec: &MutationSpec,
        ctx: &AnalysisContext,
    ) -> Result<Vec<Box<dyn ASTRegApply>>, ConvertError> {
        match spec {
            MutationSpec::ExtractTrait {
                target: target_symbol,
                trait_name,
                methods,
            } => {
                // Resolve target_symbol to SymbolId
                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;
                let mut mutation = ExtractTraitMutation::new(symbol_id, trait_name);
                if let Some(m) = methods {
                    mutation = mutation.with_methods(m.clone());
                }
                Ok(vec![Box::new(mutation)])
            }

            MutationSpec::InlineTrait {
                target: target_symbol,
                struct_name,
                remove_trait,
            } => {
                // Resolve target_symbol to SymbolId
                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;
                let mut mutation = InlineTraitMutation::new(symbol_id, struct_name);
                if !remove_trait {
                    mutation = mutation.keep_trait();
                }
                Ok(vec![Box::new(mutation)])
            }

            MutationSpec::EnumToTrait {
                target: target_symbol,
                trait_name,
                remove_enum,
                strategy,
                match_handling,
            } => {
                // Resolve target_symbol to SymbolId
                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;

                let mut mutation = EnumToTraitMutation::from_symbol_id(symbol_id)
                    .with_strategy(*strategy)
                    .with_match_handling(*match_handling);
                if let Some(t_name) = trait_name {
                    mutation = mutation.with_trait_name(t_name);
                }
                if !remove_enum {
                    mutation = mutation.keep_enum();
                }
                Ok(vec![Box::new(mutation)])
            }

            _ => Err(ConvertError::TypeMismatch {
                expected: "ExtractTrait, InlineTrait, or EnumToTrait",
                actual: spec.kind_name().to_string(),
            }),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_trait_converter_spec_kinds() {
        let converter = TraitConverter::new();
        assert_eq!(
            converter.spec_kinds(),
            &["ExtractTrait", "InlineTrait", "EnumToTrait"]
        );
    }
}