Skip to main content

ryo_executor/executor/registry/converters/
enum_.rs

1//! EnumConverter: Converts MutationSpec::AddVariant and RemoveVariant
2
3use crate::engine::ASTRegApply;
4use crate::executor::registry::converters::ResolveTargetSymbol;
5use crate::executor::registry::{ConvertError, MutationConverter};
6use crate::executor::spec::{MutationSpec, VariantKind};
7use ryo_analysis::AnalysisContext;
8use ryo_mutations::{AddVariantMutation, RemoveVariantMutation};
9
10/// Converter for Enum variant mutations (AddVariant, RemoveVariant)
11#[derive(Debug, Clone, Default)]
12pub struct EnumConverter;
13
14impl EnumConverter {
15    pub fn new() -> Self {
16        Self
17    }
18}
19
20// EnumConverter uses the default implementation of ResolveTargetSymbol
21impl ResolveTargetSymbol for EnumConverter {}
22
23impl MutationConverter for EnumConverter {
24    fn spec_kinds(&self) -> &'static [&'static str] {
25        &["AddVariant", "RemoveVariant"]
26    }
27
28    fn convert_v2(
29        &self,
30        spec: &MutationSpec,
31        ctx: &AnalysisContext,
32    ) -> Result<Vec<Box<dyn ASTRegApply>>, ConvertError> {
33        use ryo_source::pure::{PureField, PureFields, PureTupleField, PureType, PureVis};
34
35        match spec {
36            MutationSpec::AddVariant {
37                target: target_symbol,
38                variant_name,
39                variant_kind,
40            } => {
41                // Resolve target_symbol to SymbolId
42                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;
43
44                let fields = match variant_kind {
45                    VariantKind::Unit => PureFields::Unit,
46                    VariantKind::Tuple { types } => PureFields::Tuple(
47                        types
48                            .iter()
49                            .map(|t| PureTupleField {
50                                attrs: Vec::new(),
51                                vis: PureVis::Private,
52                                ty: PureType::Path(t.clone()),
53                            })
54                            .collect(),
55                    ),
56                    VariantKind::Struct { fields } => {
57                        let pure_fields: Vec<PureField> = fields
58                            .iter()
59                            .map(|(n, t)| PureField {
60                                attrs: Vec::new(),
61                                vis: PureVis::Private,
62                                name: n.clone(),
63                                ty: PureType::Path(t.clone()),
64                            })
65                            .collect();
66                        PureFields::Named(pure_fields)
67                    }
68                };
69                let mutation = AddVariantMutation::new(symbol_id, variant_name, fields);
70                Ok(vec![Box::new(mutation)])
71            }
72            MutationSpec::RemoveVariant {
73                target: target_symbol,
74                variant_name,
75            } => {
76                // Resolve target_symbol to SymbolId
77                let symbol_id = self.resolve_target_symbol(target_symbol, ctx)?;
78                let mutation = RemoveVariantMutation::new(symbol_id, variant_name);
79                Ok(vec![Box::new(mutation)])
80            }
81            _ => Err(ConvertError::TypeMismatch {
82                expected: "AddVariant or RemoveVariant",
83                actual: spec.kind_name().to_string(),
84            }),
85        }
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use crate::executor::spec::MutationTargetSymbol;
93    use ryo_symbol::{SymbolKind, SymbolPath, SymbolRegistry};
94
95    fn create_test_symbol_id() -> ryo_symbol::SymbolId {
96        let mut registry = SymbolRegistry::new();
97        let path = SymbolPath::parse("test_crate::Status").unwrap();
98        registry.register(path, SymbolKind::Enum).unwrap()
99    }
100
101    #[test]
102    fn test_enum_converter_spec_kinds() {
103        let converter = EnumConverter::new();
104        assert_eq!(converter.spec_kinds(), &["AddVariant", "RemoveVariant"]);
105    }
106
107    #[test]
108    fn test_enum_converter_can_handle_add_variant() {
109        let converter = EnumConverter::new();
110        let id = create_test_symbol_id();
111
112        let spec = MutationSpec::AddVariant {
113            target: MutationTargetSymbol::ById(id),
114            variant_name: "Pending".into(),
115            variant_kind: VariantKind::Unit,
116        };
117        assert!(converter.can_handle(&spec));
118    }
119
120    #[test]
121    fn test_enum_converter_can_handle_remove_variant() {
122        let converter = EnumConverter::new();
123        let id = create_test_symbol_id();
124
125        let spec = MutationSpec::RemoveVariant {
126            target: MutationTargetSymbol::ById(id),
127            variant_name: "Pending".into(),
128        };
129        assert!(converter.can_handle(&spec));
130    }
131}