ryo-mutations 0.1.0

[experimental] Code transformation primitives for Rust source code
Documentation
//! Struct mutations: AddStructMutation, RemoveStructMutation

use ryo_symbol::SymbolId;

use crate::Mutation;

/// Field definition for AddStructMutation
#[derive(Debug, Clone)]
pub struct StructFieldDef {
    pub name: String,
    pub ty: String,
    pub is_pub: bool,
}

impl StructFieldDef {
    pub fn new(name: impl Into<String>, ty: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            ty: ty.into(),
            is_pub: false,
        }
    }

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

/// Add a new struct to the file
#[derive(Debug, Clone)]
pub struct AddStructMutation {
    /// Parent module SymbolId where the struct should be added
    pub parent: SymbolId,
    pub name: String,
    pub fields: Vec<StructFieldDef>,
    pub is_pub: bool,
    pub derives: Vec<String>,
}

impl AddStructMutation {
    pub fn new(parent: SymbolId, name: impl Into<String>) -> Self {
        Self {
            parent,
            name: name.into(),
            fields: Vec::new(),
            is_pub: false,
            derives: Vec::new(),
        }
    }

    pub fn with_field(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
        self.fields.push(StructFieldDef::new(name, ty));
        self
    }

    /// Add a public field
    pub fn with_pub_field(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
        self.fields.push(StructFieldDef::new(name, ty).public());
        self
    }

    /// Add fields from (name, type) tuples - all private (legacy compatibility)
    pub fn with_fields(mut self, fields: Vec<(String, String)>) -> Self {
        self.fields = fields
            .into_iter()
            .map(|(name, ty)| StructFieldDef::new(name, ty))
            .collect();
        self
    }

    /// Add fields with visibility information
    pub fn with_fields_vis(mut self, fields: Vec<(String, String, bool)>) -> Self {
        self.fields = fields
            .into_iter()
            .map(|(name, ty, is_pub)| {
                let mut f = StructFieldDef::new(name, ty);
                if is_pub {
                    f = f.public();
                }
                f
            })
            .collect();
        self
    }

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

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

impl Mutation for AddStructMutation {
    fn describe(&self) -> String {
        let vis = if self.is_pub { "pub " } else { "" };
        let fields: Vec<_> = self
            .fields
            .iter()
            .map(|f| {
                let field_vis = if f.is_pub { "pub " } else { "" };
                format!("{}{}: {}", field_vis, f.name, f.ty)
            })
            .collect();
        format!(
            "Add {}struct {} {{ {} }} to {}",
            vis,
            self.name,
            fields.join(", "),
            self.parent
        )
    }

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

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

/// Remove a struct from the file
#[derive(Debug, Clone)]
pub struct RemoveStructMutation {
    /// SymbolId of the struct to remove (required, O(1) access)
    pub struct_id: SymbolId,
}

impl RemoveStructMutation {
    pub fn new(struct_id: SymbolId) -> Self {
        Self { struct_id }
    }
}

impl Mutation for RemoveStructMutation {
    fn describe(&self) -> String {
        format!("Remove struct {}", self.struct_id)
    }

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

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