ryo-executor 0.1.0

[experimental] Mutation execution engine for RYO - parallel execution, conflict detection, workspace management
Documentation
//! EnumConverter: Converts MutationSpec::AddVariant and RemoveVariant

use crate::engine::ASTRegApply;
use crate::executor::registry::converters::ResolveTargetSymbol;
use crate::executor::registry::{ConvertError, MutationConverter};
use crate::executor::spec::{MutationSpec, VariantKind};
use ryo_analysis::AnalysisContext;
use ryo_mutations::{AddVariantMutation, RemoveVariantMutation};

/// Converter for Enum variant mutations (AddVariant, RemoveVariant)
#[derive(Debug, Clone, Default)]
pub struct EnumConverter;

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

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

impl MutationConverter for EnumConverter {
    fn spec_kinds(&self) -> &'static [&'static str] {
        &["AddVariant", "RemoveVariant"]
    }

    fn convert_v2(
        &self,
        spec: &MutationSpec,
        ctx: &AnalysisContext,
    ) -> Result<Vec<Box<dyn ASTRegApply>>, ConvertError> {
        use ryo_source::pure::{PureField, PureFields, PureType, PureVis};

        match spec {
            MutationSpec::AddVariant {
                target: target_symbol,
                variant_name,
                variant_kind,
            } => {
                // Resolve target_symbol to SymbolId
                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;

                let fields = match variant_kind {
                    VariantKind::Unit => PureFields::Unit,
                    VariantKind::Tuple { types } => {
                        PureFields::Tuple(types.iter().map(|t| PureType::Path(t.clone())).collect())
                    }
                    VariantKind::Struct { fields } => {
                        let pure_fields: Vec<PureField> = fields
                            .iter()
                            .map(|(n, t)| PureField {
                                attrs: Vec::new(),
                                vis: PureVis::Private,
                                name: n.clone(),
                                ty: PureType::Path(t.clone()),
                            })
                            .collect();
                        PureFields::Named(pure_fields)
                    }
                };
                let mutation = AddVariantMutation::new(symbol_id, variant_name, fields);
                Ok(vec![Box::new(mutation)])
            }
            MutationSpec::RemoveVariant {
                target: target_symbol,
                variant_name,
            } => {
                // Resolve target_symbol to SymbolId
                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;
                let mutation = RemoveVariantMutation::new(symbol_id, variant_name);
                Ok(vec![Box::new(mutation)])
            }
            _ => Err(ConvertError::TypeMismatch {
                expected: "AddVariant or RemoveVariant",
                actual: spec.kind_name().to_string(),
            }),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::executor::spec::MutationTargetSymbol;
    use ryo_symbol::{SymbolKind, SymbolPath, SymbolRegistry};

    fn create_test_symbol_id() -> ryo_symbol::SymbolId {
        let mut registry = SymbolRegistry::new();
        let path = SymbolPath::parse("test_crate::Status").unwrap();
        registry.register(path, SymbolKind::Enum).unwrap()
    }

    #[test]
    fn test_enum_converter_spec_kinds() {
        let converter = EnumConverter::new();
        assert_eq!(converter.spec_kinds(), &["AddVariant", "RemoveVariant"]);
    }

    #[test]
    fn test_enum_converter_can_handle_add_variant() {
        let converter = EnumConverter::new();
        let id = create_test_symbol_id();

        let spec = MutationSpec::AddVariant {
            target: MutationTargetSymbol::ById(id),
            variant_name: "Pending".into(),
            variant_kind: VariantKind::Unit,
        };
        assert!(converter.can_handle(&spec));
    }

    #[test]
    fn test_enum_converter_can_handle_remove_variant() {
        let converter = EnumConverter::new();
        let id = create_test_symbol_id();

        let spec = MutationSpec::RemoveVariant {
            target: MutationTargetSymbol::ById(id),
            variant_name: "Pending".into(),
        };
        assert!(converter.can_handle(&spec));
    }
}