ryo-mutations 0.1.0

[experimental] Code transformation primitives for Rust source code
Documentation
//! Enum mutations: AddEnumMutation, RemoveEnumMutation, AddVariantMutation, RemoveVariantMutation

use ryo_source::pure::{PureField, PureFields, PureType, PureVis};
use ryo_symbol::SymbolId;

use crate::Mutation;

/// Add a new enum to the file
#[derive(Debug, Clone)]
pub struct AddEnumMutation {
    /// Parent module SymbolId
    pub parent: SymbolId,
    pub name: String,
    pub variants: Vec<(String, PureFields)>, // (variant_name, fields)
    pub is_pub: bool,
    pub derives: Vec<String>,
}

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

    pub fn with_variant(mut self, name: impl Into<String>) -> Self {
        self.variants.push((name.into(), PureFields::Unit));
        self
    }

    pub fn with_tuple_variant(mut self, name: impl Into<String>, types: Vec<String>) -> Self {
        let fields: Vec<PureType> = types.into_iter().map(PureType::Path).collect();
        self.variants.push((name.into(), PureFields::Tuple(fields)));
        self
    }

    pub fn with_struct_variant(
        mut self,
        name: impl Into<String>,
        fields: Vec<(String, String)>,
    ) -> Self {
        let pure_fields: Vec<PureField> = fields
            .into_iter()
            .map(|(n, t)| PureField {
                attrs: Vec::new(),
                vis: PureVis::Private,
                name: n,
                ty: PureType::Path(t),
            })
            .collect();
        self.variants
            .push((name.into(), PureFields::Named(pure_fields)));
        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 AddEnumMutation {
    fn describe(&self) -> String {
        let vis = if self.is_pub { "pub " } else { "" };
        format!(
            "Add {}enum {} with {} variants to {}",
            vis,
            self.name,
            self.variants.len(),
            self.parent
        )
    }

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

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

/// Remove an enum from the file
#[derive(Debug, Clone)]
pub struct RemoveEnumMutation {
    pub symbol_id: SymbolId,
}

impl RemoveEnumMutation {
    pub fn new(symbol_id: SymbolId) -> Self {
        Self { symbol_id }
    }
}

impl Mutation for RemoveEnumMutation {
    fn describe(&self) -> String {
        format!("Remove enum {}", self.symbol_id)
    }

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

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

/// Add a variant to an existing enum
#[derive(Debug, Clone)]
pub struct AddVariantMutation {
    pub enum_id: SymbolId,
    pub variant_name: String,
    pub fields: PureFields,
}

impl AddVariantMutation {
    pub fn new(enum_id: SymbolId, variant_name: impl Into<String>, fields: PureFields) -> Self {
        Self {
            enum_id,
            variant_name: variant_name.into(),
            fields,
        }
    }

    pub fn unit(enum_id: SymbolId, variant_name: impl Into<String>) -> Self {
        Self::new(enum_id, variant_name, PureFields::Unit)
    }

    pub fn tuple(enum_id: SymbolId, variant_name: impl Into<String>, types: Vec<String>) -> Self {
        Self::new(
            enum_id,
            variant_name,
            PureFields::Tuple(types.into_iter().map(PureType::Path).collect()),
        )
    }

    pub fn struct_variant(
        enum_id: SymbolId,
        variant_name: impl Into<String>,
        fields: Vec<(String, String)>,
    ) -> Self {
        let pure_fields: Vec<PureField> = fields
            .into_iter()
            .map(|(n, t)| PureField {
                attrs: Vec::new(),
                vis: PureVis::Private,
                name: n,
                ty: PureType::Path(t),
            })
            .collect();
        Self::new(enum_id, variant_name, PureFields::Named(pure_fields))
    }
}

impl Mutation for AddVariantMutation {
    fn describe(&self) -> String {
        format!("Add variant {} to enum {}", self.variant_name, self.enum_id)
    }

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

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

/// Remove a variant from an enum
#[derive(Debug, Clone)]
pub struct RemoveVariantMutation {
    /// Pre-resolved SymbolId for the target enum (required - O(1) access)
    pub enum_id: SymbolId,
    pub variant_name: String,
}

impl RemoveVariantMutation {
    pub fn new(enum_id: SymbolId, variant_name: impl Into<String>) -> Self {
        Self {
            enum_id,
            variant_name: variant_name.into(),
        }
    }
}

impl Mutation for RemoveVariantMutation {
    fn describe(&self) -> String {
        format!(
            "Remove variant {} from enum {}",
            self.variant_name, self.enum_id
        )
    }

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

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