mago-database 1.0.0-alpha.5

Provides a high-performance, in-memory database for source code analysis, featuring distinct mutable and immutable states and transactional updates.
Documentation
use globset::Error as GlobSetError;

/// The primary error type for all database loading and mutation operations.
///
/// This enum consolidates errors from various sources, including file I/O,
/// pattern matching, and concurrent access issues, into a single, unified type.
#[derive(Debug)]
pub enum DatabaseError {
    /// An attempt was made to access a file that does not exist in the database.
    FileNotFound,
    /// An error occurred during a filesystem read or write operation.
    IOError(std::io::Error),
    /// The set of user-provided glob patterns could not be compiled into a `GlobSet`.
    InvalidGlobSet(GlobSetError),
    /// An attempt was made to commit or consume a `ChangeLog` while other
    /// references to it still exist, indicating that other threads may not have
    /// finished their work.
    ChangeLogInUse,
    /// The lock on a `ChangeLog` was "poisoned."
    ///
    /// This happens when a thread panics while holding the lock, leaving the
    /// data in an unrecoverable and potentially inconsistent state.
    PoisonedLogMutex,
}

impl std::fmt::Display for DatabaseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::FileNotFound => write!(f, "file not found in database"),
            Self::IOError(err) => write!(f, "I/O error: {err}"),
            Self::InvalidGlobSet(err) => write!(f, "failed to build exclusion filter from patterns: {err}"),
            Self::ChangeLogInUse => {
                write!(f, "cannot commit changelog because it is still in use by another thread")
            }
            Self::PoisonedLogMutex => {
                write!(f, "changelog is in an unrecoverable state because a thread panicked while modifying it")
            }
        }
    }
}

impl std::error::Error for DatabaseError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::IOError(err) => Some(err),
            Self::InvalidGlobSet(err) => Some(err),
            _ => None,
        }
    }
}

impl From<std::io::Error> for DatabaseError {
    fn from(error: std::io::Error) -> Self {
        Self::IOError(error)
    }
}

impl From<GlobSetError> for DatabaseError {
    fn from(error: GlobSetError) -> Self {
        Self::InvalidGlobSet(error)
    }
}