use ryo_mutations::basic::{AddUseMutation, RemoveUseMutation};
use ryo_mutations::MutationResult;
use ryo_source::pure::{PureItem, PureUse, PureUseTree, PureVis};
use ryo_symbol::SymbolKind;
use crate::engine::{ASTMutationContext, ASTRegApply};
impl ASTRegApply for AddUseMutation {
fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
let module_id = ctx
.symbol_registry
.iter()
.filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Mod))
.find(|(_, path)| path.to_string() == "crate")
.map(|(id, _)| id);
let module_id = match module_id {
Some(id) => id,
None => {
return MutationResult {
mutation_type: "AddUse".to_string(),
changes: 0,
description: "Crate root module not found".to_string(),
};
}
};
let exists = ctx
.symbol_registry
.iter()
.filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Use))
.any(|(_, path)| path.name() == self.path);
if exists {
return MutationResult {
mutation_type: "AddUse".to_string(),
changes: 0,
description: format!("Use statement '{}' already exists", self.path),
};
}
let tree = parse_path_to_tree(&self.path);
let use_item = PureUse {
vis: PureVis::Private,
tree,
};
let use_path = ctx
.symbol_registry
.path(module_id)
.and_then(|p| p.child(&self.path).ok());
if let Some(path) = use_path {
if let Ok(use_id) = ctx.symbol_registry.register(path, SymbolKind::Use) {
ctx.ast_registry.set(use_id, PureItem::Use(use_item));
return MutationResult {
mutation_type: "AddUse".to_string(),
changes: 1,
description: format!("Added use statement '{}'", self.path),
};
}
}
MutationResult {
mutation_type: "AddUse".to_string(),
changes: 0,
description: format!("Failed to register use statement '{}'", self.path),
}
}
}
impl ASTRegApply for RemoveUseMutation {
fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
let use_id = ctx
.symbol_registry
.iter()
.filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Use))
.find(|(_, path)| {
if self.path.contains("::") {
path.to_string() == self.path || path.name() == self.path
} else {
path.name() == self.path
}
})
.map(|(id, _)| id);
let use_id = match use_id {
Some(id) => id,
None => {
return MutationResult {
mutation_type: "RemoveUse".to_string(),
changes: 0,
description: format!("Use statement '{}' not found", self.path),
};
}
};
ctx.ast_registry.remove(use_id);
MutationResult {
mutation_type: "RemoveUse".to_string(),
changes: 1,
description: format!("Removed use statement '{}'", self.path),
}
}
}
fn parse_path_to_tree(path: &str) -> PureUseTree {
let parts: Vec<&str> = path.split("::").collect();
if parts.is_empty() {
return PureUseTree::Name(path.to_string());
}
let mut tree = PureUseTree::Name(
parts
.last()
.expect("is_empty() guard above guarantees a last element")
.to_string(),
);
for part in parts.iter().rev().skip(1) {
tree = PureUseTree::Path {
path: part.to_string(),
tree: Box::new(tree),
};
}
tree
}