use crate::engine::ASTRegApply;
use crate::executor::registry::converters::ResolveTargetSymbol;
use crate::executor::registry::{ConvertError, MutationConverter};
use crate::executor::spec::{MutationSpec, Visibility};
use ryo_analysis::AnalysisContext;
use ryo_mutations::{AddFieldMutation, RemoveFieldMutation};
#[derive(Debug, Clone, Default)]
pub struct FieldConverter;
impl FieldConverter {
pub fn new() -> Self {
Self
}
}
impl ResolveTargetSymbol for FieldConverter {}
impl MutationConverter for FieldConverter {
fn spec_kinds(&self) -> &'static [&'static str] {
&["AddField", "RemoveField"]
}
fn convert_v2(
&self,
spec: &MutationSpec,
ctx: &AnalysisContext,
) -> Result<Vec<Box<dyn ASTRegApply>>, ConvertError> {
match spec {
MutationSpec::AddField {
target,
field_name,
field_type,
visibility,
} => {
let symbol_id = self.resolve_target_symbol(target, ctx)?;
let mut mutation = AddFieldMutation::new(symbol_id, field_name, field_type);
if *visibility == Visibility::Pub {
mutation = mutation.public();
}
Ok(vec![Box::new(mutation)])
}
MutationSpec::RemoveField { target, field_name } => {
let symbol_id = self.resolve_target_symbol(target, ctx)?;
let mutation = RemoveFieldMutation::new(symbol_id, field_name);
Ok(vec![Box::new(mutation)])
}
_ => Err(ConvertError::TypeMismatch {
expected: "AddField or RemoveField",
actual: spec.kind_name().to_string(),
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_field_converter_spec_kinds() {
let converter = FieldConverter::new();
assert_eq!(converter.spec_kinds(), &["AddField", "RemoveField"]);
}
#[test]
fn test_field_converter_can_handle_add() {
use crate::executor::spec::MutationTargetSymbol;
use ryo_symbol::{SymbolKind, SymbolPath, SymbolRegistry};
let converter = FieldConverter::new();
let mut registry = SymbolRegistry::new();
let path = SymbolPath::parse("test_crate::Config").unwrap();
let symbol_id = registry.register(path, SymbolKind::Struct).unwrap();
let spec = MutationSpec::AddField {
target: MutationTargetSymbol::by_id(symbol_id),
field_name: "timeout".into(),
field_type: "u64".into(),
visibility: Visibility::Pub,
};
assert!(converter.can_handle(&spec));
}
#[test]
fn test_field_converter_can_handle_remove() {
use crate::executor::spec::MutationTargetSymbol;
use ryo_symbol::{SymbolKind, SymbolPath, SymbolRegistry};
let converter = FieldConverter::new();
let mut registry = SymbolRegistry::new();
let path = SymbolPath::parse("test_crate::Config").unwrap();
let symbol_id = registry.register(path, SymbolKind::Struct).unwrap();
let spec = MutationSpec::RemoveField {
target: MutationTargetSymbol::by_id(symbol_id),
field_name: "timeout".into(),
};
assert!(converter.can_handle(&spec));
}
}