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};
pub struct TraitConverter;
impl TraitConverter {
pub fn new() -> Self {
Self
}
}
impl Default for TraitConverter {
fn default() -> Self {
Self::new()
}
}
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,
} => {
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,
} => {
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,
} => {
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"]
);
}
}