Skip to main content

hora_graph_core/
error.rs

1//! Error types for hora-graph-core operations.
2
3use std::fmt;
4
5/// All errors returned by hora-graph-core.
6#[derive(Debug)]
7#[non_exhaustive]
8pub enum HoraError {
9    // Storage
10    /// An I/O error occurred.
11    Io(std::io::Error),
12    /// A page failed its CRC32 integrity check.
13    CorruptedFile {
14        /// Page number that failed verification.
15        page: u32,
16        /// Checksum stored in the page header.
17        expected_checksum: u32,
18        /// Checksum computed from the page data.
19        actual_checksum: u32,
20    },
21    /// The file is structurally invalid (bad magic, header, etc.).
22    InvalidFile {
23        /// Human-readable reason for the failure.
24        reason: &'static str,
25    },
26    /// The file was written by an unsupported version of the engine.
27    VersionMismatch {
28        /// Version number found in the file.
29        file_version: u16,
30        /// Minimum version this build can read.
31        min_supported: u16,
32        /// Maximum version this build can read.
33        max_supported: u16,
34    },
35
36    // Schema / Input
37    /// No entity exists with the given ID.
38    EntityNotFound(u64),
39    /// No edge exists with the given ID.
40    EdgeNotFound(u64),
41    /// Embedding dimension does not match the configured value.
42    DimensionMismatch {
43        /// Dimension expected by the engine.
44        expected: usize,
45        /// Dimension provided by the caller.
46        got: usize,
47    },
48    /// The fact has already been invalidated (bi-temporal soft-delete).
49    AlreadyInvalidated(u64),
50
51    // Capacity
52    /// A string value exceeds the maximum allowed byte length.
53    StringTooLong {
54        /// Maximum allowed byte length.
55        max: usize,
56        /// Actual byte length provided.
57        got: usize,
58    },
59    /// The storage backend has no space left to allocate new pages.
60    StorageFull,
61
62    // SQLite backend
63    /// A SQLite backend error.
64    #[cfg(feature = "sqlite")]
65    Sqlite(String),
66
67    // PostgreSQL backend
68    /// A PostgreSQL backend error.
69    #[cfg(feature = "postgres")]
70    Postgres(String),
71}
72
73impl fmt::Display for HoraError {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        match self {
76            Self::Io(e) => write!(f, "I/O error: {}", e),
77            Self::CorruptedFile {
78                page,
79                expected_checksum,
80                actual_checksum,
81            } => write!(
82                f,
83                "corrupted page {}: expected checksum 0x{:08x}, got 0x{:08x}",
84                page, expected_checksum, actual_checksum
85            ),
86            Self::InvalidFile { reason } => write!(f, "invalid .hora file: {}", reason),
87            Self::VersionMismatch {
88                file_version,
89                min_supported,
90                max_supported,
91            } => write!(
92                f,
93                "version {} not supported (supported: {}-{})",
94                file_version, min_supported, max_supported
95            ),
96            Self::EntityNotFound(id) => write!(f, "entity {} not found", id),
97            Self::EdgeNotFound(id) => write!(f, "edge {} not found", id),
98            Self::DimensionMismatch { expected, got } => {
99                write!(
100                    f,
101                    "embedding dimension mismatch: expected {}, got {}",
102                    expected, got
103                )
104            }
105            Self::AlreadyInvalidated(id) => write!(f, "fact {} is already invalidated", id),
106            Self::StringTooLong { max, got } => {
107                write!(f, "string too long: max {} bytes, got {}", max, got)
108            }
109            Self::StorageFull => write!(f, "storage is full"),
110            #[cfg(feature = "sqlite")]
111            Self::Sqlite(msg) => write!(f, "SQLite error: {}", msg),
112            #[cfg(feature = "postgres")]
113            Self::Postgres(msg) => write!(f, "PostgreSQL error: {}", msg),
114        }
115    }
116}
117
118impl std::error::Error for HoraError {
119    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
120        match self {
121            Self::Io(e) => Some(e),
122            _ => None,
123        }
124    }
125}
126
127impl From<std::io::Error> for HoraError {
128    fn from(e: std::io::Error) -> Self {
129        Self::Io(e)
130    }
131}
132
133/// Result type alias for hora-graph-core operations.
134pub type Result<T> = std::result::Result<T, HoraError>;