use ryo_mutations::basic::{AddStructMutation, RemoveStructMutation};
use ryo_mutations::MutationResult;
use ryo_source::pure::{
PureAttrMeta, PureAttribute, PureField, PureFields, PureGenerics, PureItem, PureStruct,
PureType, PureVis,
};
use ryo_symbol::SymbolKind;
use crate::engine::{ASTMutationContext, ASTRegApply};
impl ASTRegApply for AddStructMutation {
fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
let module_id = self.parent;
if ctx.symbol_registry.kind(module_id) != Some(SymbolKind::Mod) {
return MutationResult {
mutation_type: "AddStruct".to_string(),
changes: 0,
description: format!("Symbol {} is not a module", module_id),
};
}
let exists = ctx
.symbol_registry
.iter()
.filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Struct))
.any(|(_, path)| path.name() == self.name);
if exists {
return MutationResult {
mutation_type: "AddStruct".to_string(),
changes: 0,
description: format!("Struct '{}' already exists", self.name),
};
}
let attrs = if !self.derives.is_empty() {
vec![PureAttribute {
path: "derive".to_string(),
meta: PureAttrMeta::List(self.derives.join(", ")),
is_inner: false,
}]
} else {
vec![]
};
let fields: Vec<PureField> = self
.fields
.iter()
.map(|f| PureField {
attrs: vec![],
vis: if f.is_pub {
PureVis::Public
} else {
PureVis::Private
},
name: f.name.clone(),
ty: PureType::Path(f.ty.clone()),
})
.collect();
let struct_item = PureStruct {
attrs,
vis: if self.is_pub {
PureVis::Public
} else {
PureVis::Private
},
name: self.name.clone(),
generics: PureGenerics::default(),
fields: if fields.is_empty() {
PureFields::Unit
} else {
PureFields::Named(fields)
},
};
let struct_path = ctx
.symbol_registry
.path(module_id)
.and_then(|p| p.child(&self.name).ok());
if let Some(path) = struct_path {
if let Ok(struct_id) = ctx.symbol_registry.register(path, SymbolKind::Struct) {
ctx.ast_registry
.set(struct_id, PureItem::Struct(struct_item));
return MutationResult {
mutation_type: "AddStruct".to_string(),
changes: 1,
description: format!("Added struct '{}'", self.name),
};
}
}
MutationResult {
mutation_type: "AddStruct".to_string(),
changes: 0,
description: format!("Failed to register struct '{}'", self.name),
}
}
}
impl ASTRegApply for RemoveStructMutation {
fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
let struct_id = self.struct_id;
if ctx.symbol_registry.kind(struct_id) != Some(SymbolKind::Struct) {
return MutationResult {
mutation_type: "RemoveStruct".to_string(),
changes: 0,
description: format!("Symbol {} is not a struct", struct_id),
};
}
ctx.ast_registry.remove(struct_id);
MutationResult {
mutation_type: "RemoveStruct".to_string(),
changes: 1,
description: format!("Removed struct {}", struct_id),
}
}
}