mago_database/
error.rs

1use std::path::PathBuf;
2
3use globset::Error as GlobSetError;
4
5/// The primary error type for all database loading and mutation operations.
6///
7/// This enum consolidates errors from various sources, including file I/O,
8/// pattern matching, and concurrent access issues, into a single, unified type.
9#[derive(Debug)]
10pub enum DatabaseError {
11    /// An attempt was made to access a file that does not exist in the database.
12    FileNotFound,
13    /// An error occurred during a filesystem read or write operation.
14    IOError(std::io::Error),
15    /// The set of user-provided glob patterns could not be compiled into a `GlobSet`.
16    InvalidGlobSet(GlobSetError),
17    /// The file being loaded into the database is too large to be processed.
18    FileTooLarge(PathBuf, usize, usize),
19    /// An attempt was made to commit or consume a `ChangeLog` while other
20    /// references to it still exist, indicating that other threads may not have
21    /// finished their work.
22    ChangeLogInUse,
23    /// The lock on a `ChangeLog` was "poisoned."
24    ///
25    /// This happens when a thread panics while holding the lock, leaving the
26    /// data in an unrecoverable and potentially inconsistent state.
27    PoisonedLogMutex,
28}
29
30impl std::fmt::Display for DatabaseError {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        match self {
33            Self::FileNotFound => write!(f, "file not found in database"),
34            Self::IOError(err) => write!(f, "I/O error: {err}"),
35            Self::InvalidGlobSet(err) => write!(f, "failed to build exclusion filter from patterns: {err}"),
36            Self::FileTooLarge(path, size, max_size) => {
37                write!(
38                    f,
39                    "file at {} is too large to be processed: {} bytes (maximum is {} bytes)",
40                    path.display(),
41                    size,
42                    max_size
43                )
44            }
45            Self::ChangeLogInUse => {
46                write!(f, "cannot commit changelog because it is still in use by another thread")
47            }
48            Self::PoisonedLogMutex => {
49                write!(f, "changelog is in an unrecoverable state because a thread panicked while modifying it")
50            }
51        }
52    }
53}
54
55impl std::error::Error for DatabaseError {
56    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
57        match self {
58            Self::IOError(err) => Some(err),
59            Self::InvalidGlobSet(err) => Some(err),
60            _ => None,
61        }
62    }
63}
64
65impl From<std::io::Error> for DatabaseError {
66    fn from(error: std::io::Error) -> Self {
67        Self::IOError(error)
68    }
69}
70
71impl From<GlobSetError> for DatabaseError {
72    fn from(error: GlobSetError) -> Self {
73        Self::InvalidGlobSet(error)
74    }
75}