herolib-code 0.3.13

Code analysis and parsing utilities for Rust source files
Documentation
//! Type definitions for parsed Rust code structures.
//!
//! This module defines the data structures used to represent parsed Rust code elements
//! including enumerators, structs, methods, and their associated documentation.

use serde::{Deserialize, Serialize};

/// Represents a parsed Rust codebase containing all discovered code elements.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CodeBase {
    /// All discovered enumerators in the codebase.
    pub enums: Vec<EnumInfo>,
    /// All discovered structs in the codebase.
    pub structs: Vec<StructInfo>,
    /// Source files that were parsed.
    pub files: Vec<FileInfo>,
}

impl CodeBase {
    /// Creates a new empty CodeBase.
    pub fn new() -> Self {
        Self::default()
    }

    /// Merges another CodeBase into this one.
    pub fn merge(&mut self, other: CodeBase) {
        self.enums.extend(other.enums);
        self.structs.extend(other.structs);
        self.files.extend(other.files);
    }

    /// Returns the total number of code elements.
    pub fn total_elements(&self) -> usize {
        self.enums.len() + self.structs.len()
    }
}

/// Information about a parsed source file.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileInfo {
    /// The file path relative to the root directory.
    pub path: String,
    /// Number of enums found in this file.
    pub enum_count: usize,
    /// Number of structs found in this file.
    pub struct_count: usize,
}

/// Represents a parsed Rust enum with its variants and documentation.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnumInfo {
    /// The name of the enum.
    pub name: String,
    /// Documentation comment for the enum.
    pub doc_comment: Option<String>,
    /// The file where this enum is defined.
    pub file_path: String,
    /// Line number where the enum starts.
    pub line_number: usize,
    /// Visibility of the enum (pub, pub(crate), etc.).
    pub visibility: Visibility,
    /// Generic parameters if any.
    pub generics: Vec<String>,
    /// Derive macros applied to this enum.
    pub derives: Vec<String>,
    /// Other attributes on the enum.
    pub attributes: Vec<String>,
    /// Variants of the enum.
    pub variants: Vec<EnumVariant>,
}

/// Represents a single variant of an enum.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnumVariant {
    /// The name of the variant.
    pub name: String,
    /// Documentation comment for the variant.
    pub doc_comment: Option<String>,
    /// Fields of the variant (for tuple or struct variants).
    pub fields: Vec<FieldInfo>,
    /// Discriminant value if specified (e.g., `Variant = 5`).
    pub discriminant: Option<String>,
}

/// Represents a parsed Rust struct with its fields and documentation.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StructInfo {
    /// The name of the struct.
    pub name: String,
    /// Documentation comment for the struct.
    pub doc_comment: Option<String>,
    /// The file where this struct is defined.
    pub file_path: String,
    /// Line number where the struct starts.
    pub line_number: usize,
    /// Visibility of the struct.
    pub visibility: Visibility,
    /// Generic parameters if any.
    pub generics: Vec<String>,
    /// Derive macros applied to this struct.
    pub derives: Vec<String>,
    /// Other attributes on the struct.
    pub attributes: Vec<String>,
    /// Fields of the struct.
    pub fields: Vec<FieldInfo>,
    /// Methods implemented on this struct.
    pub methods: Vec<MethodInfo>,
}

/// Represents a field in a struct or enum variant.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldInfo {
    /// The name of the field (None for tuple struct fields).
    pub name: Option<String>,
    /// The type of the field as a string.
    pub ty: String,
    /// Documentation comment for the field.
    pub doc_comment: Option<String>,
    /// Visibility of the field.
    pub visibility: Visibility,
    /// Attributes on the field.
    pub attributes: Vec<String>,
}

/// Represents a method implemented on a struct.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MethodInfo {
    /// The name of the method.
    pub name: String,
    /// Documentation comment for the method.
    pub doc_comment: Option<String>,
    /// The file where this method is defined.
    pub file_path: String,
    /// Line number where the method starts.
    pub line_number: usize,
    /// Visibility of the method.
    pub visibility: Visibility,
    /// Whether this is an async method.
    pub is_async: bool,
    /// Whether this is a const method.
    pub is_const: bool,
    /// Whether this is an unsafe method.
    pub is_unsafe: bool,
    /// Generic parameters if any.
    pub generics: Vec<String>,
    /// Parameters of the method.
    pub parameters: Vec<ParameterInfo>,
    /// Return type of the method (None for `-> ()`).
    pub return_type: Option<String>,
    /// The receiver type (self, &self, &mut self, or None for associated functions).
    pub receiver: Option<Receiver>,
}

/// Represents a method parameter.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParameterInfo {
    /// The name of the parameter.
    pub name: String,
    /// The type of the parameter as a string.
    pub ty: String,
}

/// Represents the receiver of a method (self parameter).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Receiver {
    /// `self` - takes ownership.
    Value,
    /// `&self` - immutable borrow.
    Ref,
    /// `&mut self` - mutable borrow.
    RefMut,
    /// `self: Box<Self>` or other explicit receiver types.
    Explicit(String),
}

/// Represents the visibility of a Rust item.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum Visibility {
    /// Private (no visibility modifier).
    Private,
    /// `pub` - public.
    Public,
    /// `pub(crate)` - visible within the crate.
    Crate,
    /// `pub(super)` - visible to the parent module.
    Super,
    /// `pub(in path)` - visible within a specific path.
    Restricted(String),
}

impl Default for Visibility {
    fn default() -> Self {
        Visibility::Private
    }
}

impl std::fmt::Display for Visibility {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Visibility::Private => write!(f, ""),
            Visibility::Public => write!(f, "pub"),
            Visibility::Crate => write!(f, "pub(crate)"),
            Visibility::Super => write!(f, "pub(super)"),
            Visibility::Restricted(path) => write!(f, "pub(in {})", path),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_codebase_new() {
        let codebase = CodeBase::new();
        assert!(codebase.enums.is_empty());
        assert!(codebase.structs.is_empty());
        assert!(codebase.files.is_empty());
    }

    #[test]
    fn test_codebase_merge() {
        let mut codebase1 = CodeBase::new();
        codebase1.enums.push(EnumInfo {
            name: "TestEnum".to_string(),
            doc_comment: None,
            file_path: "test.rs".to_string(),
            line_number: 1,
            visibility: Visibility::Public,
            generics: vec![],
            derives: vec![],
            attributes: vec![],
            variants: vec![],
        });

        let mut codebase2 = CodeBase::new();
        codebase2.structs.push(StructInfo {
            name: "TestStruct".to_string(),
            doc_comment: None,
            file_path: "test.rs".to_string(),
            line_number: 10,
            visibility: Visibility::Public,
            generics: vec![],
            derives: vec![],
            attributes: vec![],
            fields: vec![],
            methods: vec![],
        });

        codebase1.merge(codebase2);
        assert_eq!(codebase1.enums.len(), 1);
        assert_eq!(codebase1.structs.len(), 1);
    }

    #[test]
    fn test_visibility_display() {
        assert_eq!(Visibility::Private.to_string(), "");
        assert_eq!(Visibility::Public.to_string(), "pub");
        assert_eq!(Visibility::Crate.to_string(), "pub(crate)");
        assert_eq!(Visibility::Super.to_string(), "pub(super)");
        assert_eq!(
            Visibility::Restricted("crate::module".to_string()).to_string(),
            "pub(in crate::module)"
        );
    }
}