ryo-mutations 0.1.0

[experimental] Code transformation primitives for Rust source code
Documentation
//! Method mutations: AddMethodMutation, RemoveMethodMutation

use ryo_symbol::SymbolId;

use crate::Mutation;

/// Add a method to a struct or enum
///
/// New design: Methods are registered directly on the type (e.g., `Struct::method`).
/// Impl blocks are file-level constructs, not internal entities.
#[derive(Debug, Clone)]
pub struct AddMethodMutation {
    /// SymbolId for the type (Struct or Enum)
    pub type_id: SymbolId,
    pub name: String,
    pub params: Vec<(String, String)>,
    pub return_type: Option<String>,
    pub body: String,
    pub is_pub: bool,
    pub takes_self: Option<(bool, bool)>, // Some((is_ref, is_mut)) or None
}

impl AddMethodMutation {
    pub fn new(type_id: SymbolId, name: impl Into<String>) -> Self {
        Self {
            type_id,
            name: name.into(),
            params: Vec::new(),
            return_type: None,
            body: "todo!()".to_string(),
            is_pub: false,
            takes_self: None,
        }
    }

    pub fn with_self(mut self) -> Self {
        self.takes_self = Some((true, false)); // &self
        self
    }

    pub fn with_mut_self(mut self) -> Self {
        self.takes_self = Some((true, true)); // &mut self
        self
    }

    pub fn with_owned_self(mut self) -> Self {
        self.takes_self = Some((false, false)); // self
        self
    }

    pub fn with_params(mut self, params: Vec<(String, String)>) -> Self {
        self.params = params;
        self
    }

    pub fn with_return_type(mut self, ty: impl Into<String>) -> Self {
        self.return_type = Some(ty.into());
        self
    }

    pub fn with_body(mut self, body: impl Into<String>) -> Self {
        self.body = body.into();
        self
    }

    pub fn public(mut self) -> Self {
        self.is_pub = true;
        self
    }
}

impl Mutation for AddMethodMutation {
    fn describe(&self) -> String {
        let vis = if self.is_pub { "pub " } else { "" };
        let self_param = match self.takes_self {
            Some((true, true)) => "&mut self",
            Some((true, false)) => "&self",
            Some((false, _)) => "self",
            None => "",
        };
        let ret = self
            .return_type
            .as_ref()
            .map(|t| format!(" -> {}", t))
            .unwrap_or_default();
        format!(
            "Add {}fn {}({}){}  to type {}",
            vis, self.name, self_param, ret, self.type_id
        )
    }

    fn mutation_type(&self) -> &'static str {
        "AddMethod"
    }

    fn box_clone(&self) -> Box<dyn Mutation> {
        Box::new(self.clone())
    }
}

/// Remove a method from a struct or enum
///
/// New design: Methods are registered directly on the type (e.g., `Struct::method`).
#[derive(Debug, Clone)]
pub struct RemoveMethodMutation {
    /// SymbolId for the method itself (Type::method)
    pub method_id: SymbolId,
}

impl RemoveMethodMutation {
    pub fn new(method_id: SymbolId) -> Self {
        Self { method_id }
    }
}

impl Mutation for RemoveMethodMutation {
    fn describe(&self) -> String {
        format!("Remove method {}", self.method_id)
    }

    fn mutation_type(&self) -> &'static str {
        "RemoveMethod"
    }

    fn box_clone(&self) -> Box<dyn Mutation> {
        Box::new(self.clone())
    }
}