use crate::Mutation;
use ryo_symbol::SymbolId;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum EnumToTraitStrategy {
#[default]
Dynamic,
Static,
Generic,
MarkerOnly,
}
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum MatchHandling {
#[default]
WarnOnly,
Downcast,
BlockOnMatch,
}
#[derive(Debug, Clone)]
pub struct ExtractTraitMutation {
pub symbol_id: SymbolId,
pub trait_name: String,
pub methods: Option<Vec<String>>,
}
impl ExtractTraitMutation {
pub fn new(symbol_id: SymbolId, trait_name: impl Into<String>) -> Self {
Self {
symbol_id,
trait_name: trait_name.into(),
methods: None,
}
}
pub fn with_methods(mut self, methods: Vec<String>) -> Self {
self.methods = Some(methods);
self
}
}
impl Mutation for ExtractTraitMutation {
fn describe(&self) -> String {
format!(
"Extract trait '{}' from impl (SymbolId: {:?})",
self.trait_name, self.symbol_id
)
}
fn mutation_type(&self) -> &'static str {
"ExtractTrait"
}
fn box_clone(&self) -> Box<dyn Mutation> {
Box::new(self.clone())
}
}
#[derive(Debug, Clone)]
pub struct InlineTraitMutation {
pub symbol_id: SymbolId,
pub struct_name: String,
pub remove_trait: bool, }
impl InlineTraitMutation {
pub fn new(symbol_id: SymbolId, struct_name: impl Into<String>) -> Self {
Self {
symbol_id,
struct_name: struct_name.into(),
remove_trait: true,
}
}
pub fn keep_trait(mut self) -> Self {
self.remove_trait = false;
self
}
}
impl Mutation for InlineTraitMutation {
fn describe(&self) -> String {
format!(
"Inline trait {:?} into impl {}",
self.symbol_id, self.struct_name
)
}
fn mutation_type(&self) -> &'static str {
"InlineTrait"
}
fn box_clone(&self) -> Box<dyn Mutation> {
Box::new(self.clone())
}
}
#[derive(Debug, Clone)]
pub struct RemoveTraitMutation {
pub trait_id: SymbolId,
}
impl RemoveTraitMutation {
pub fn new(trait_id: SymbolId) -> Self {
Self { trait_id }
}
}
impl Mutation for RemoveTraitMutation {
fn describe(&self) -> String {
format!("Remove trait {}", self.trait_id)
}
fn mutation_type(&self) -> &'static str {
"RemoveTrait"
}
fn box_clone(&self) -> Box<dyn Mutation> {
Box::new(self.clone())
}
}
#[derive(Debug, Clone)]
pub struct EnumToTraitMutation {
pub symbol_id: ryo_symbol::SymbolId,
pub trait_name: Option<String>,
pub remove_enum: bool,
pub variants: Vec<VariantInfo>,
pub strategy: EnumToTraitStrategy,
pub match_handling: MatchHandling,
}
#[derive(Debug, Clone)]
pub struct VariantInfo {
pub name: String,
pub fields: Vec<FieldInfo>,
}
#[derive(Debug, Clone)]
pub struct FieldInfo {
pub name: String,
pub ty: String,
}
impl EnumToTraitMutation {
pub fn from_symbol_id(symbol_id: ryo_symbol::SymbolId) -> Self {
Self {
symbol_id,
trait_name: None,
remove_enum: true,
variants: Vec::new(),
strategy: EnumToTraitStrategy::default(),
match_handling: MatchHandling::default(),
}
}
pub fn with_trait_name(mut self, name: impl Into<String>) -> Self {
self.trait_name = Some(name.into());
self
}
pub fn keep_enum(mut self) -> Self {
self.remove_enum = false;
self
}
pub fn with_variants(mut self, variants: Vec<VariantInfo>) -> Self {
self.variants = variants;
self
}
pub fn with_strategy(mut self, strategy: EnumToTraitStrategy) -> Self {
self.strategy = strategy;
self
}
pub fn with_match_handling(mut self, handling: MatchHandling) -> Self {
self.match_handling = handling;
self
}
}
impl Mutation for EnumToTraitMutation {
fn describe(&self) -> String {
let trait_name = self.trait_name.as_deref().unwrap_or("<from_enum>");
format!(
"Convert enum (symbol:{:?}) to trait '{}' with {} struct implementations",
self.symbol_id,
trait_name,
self.variants.len()
)
}
fn mutation_type(&self) -> &'static str {
"EnumToTrait"
}
fn box_clone(&self) -> Box<dyn Mutation> {
Box::new(self.clone())
}
}