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};
#[derive(Debug, Clone, Default)]
pub struct EnumConverter;
impl EnumConverter {
pub fn new() -> Self {
Self
}
}
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,
} => {
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,
} => {
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));
}
}