Skip to main content

xlog_core/
error.rs

1//! Error types for XLOG
2
3use thiserror::Error;
4
5/// Primary error type for XLOG operations
6#[derive(Debug, Error)]
7#[non_exhaustive]
8pub enum XlogError {
9    /// Parse error from the Datalog frontend.
10    #[error("Parse error: {0}")]
11    Parse(String),
12
13    /// Stratification failed due to a cycle through negation.
14    #[error("Stratification failed: cycle through negation involving {0:?}")]
15    StratificationCycle(Vec<String>),
16
17    /// A variable is not bound in any positive body literal (domain safety violation).
18    #[error("Domain safety: variable {0} not bound in positive literal")]
19    UnsafeVariable(String),
20
21    /// GPU memory budget exceeded.
22    #[error("Resource exhausted: {context}, estimated {estimated_bytes} bytes, budget {budget_bytes} bytes")]
23    ResourceExhausted {
24        /// Description of the operation that exceeded the budget.
25        context: String,
26        /// Estimated memory required in bytes.
27        estimated_bytes: u64,
28        /// Available memory budget in bytes.
29        budget_bytes: u64,
30    },
31
32    /// GPU kernel launch or execution error.
33    #[error("Kernel error: {0}")]
34    Kernel(String),
35
36    /// Type checking or inference error.
37    #[error("Type error: {0}")]
38    Type(String),
39
40    /// Compilation pipeline error.
41    #[error("Compilation error: {0}")]
42    Compilation(String),
43
44    /// Epistemic construct is known to the frontend but unsupported in this context.
45    #[error("Unsupported epistemic construct: {construct} ({context})")]
46    UnsupportedEpistemicConstruct {
47        /// Construct that was rejected.
48        construct: String,
49        /// Context where the construct was rejected.
50        context: String,
51    },
52
53    /// Runtime execution error.
54    #[error("Execution error: {0}")]
55    Execution(String),
56}
57
58impl XlogError {
59    /// Create a Kernel error with structured context: "op: detail: source".
60    pub fn kernel_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
61        XlogError::Kernel(format!("{op}: {detail}: {source}"))
62    }
63
64    /// Create an Execution error with structured context.
65    pub fn execution_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
66        XlogError::Execution(format!("{op}: {detail}: {source}"))
67    }
68
69    /// Create a Compilation error with structured context.
70    pub fn compilation_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
71        XlogError::Compilation(format!("{op}: {detail}: {source}"))
72    }
73}
74
75/// Result alias using XlogError
76pub type Result<T> = std::result::Result<T, XlogError>;
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_parse_error_display() {
84        let err = XlogError::Parse("unexpected token".to_string());
85        assert_eq!(err.to_string(), "Parse error: unexpected token");
86    }
87
88    #[test]
89    fn test_stratification_cycle_display() {
90        let err = XlogError::StratificationCycle(vec!["foo".to_string(), "bar".to_string()]);
91        assert!(err.to_string().contains("foo"));
92        assert!(err.to_string().contains("bar"));
93    }
94
95    #[test]
96    fn test_resource_exhausted_display() {
97        let err = XlogError::ResourceExhausted {
98            context: "join operation".to_string(),
99            estimated_bytes: 1024,
100            budget_bytes: 512,
101        };
102        assert!(err.to_string().contains("1024"));
103        assert!(err.to_string().contains("512"));
104    }
105
106    #[test]
107    fn test_kernel_ctx() {
108        let err = XlogError::kernel_ctx("download_column", "dtoh copy failed", &"device error 42");
109        assert_eq!(
110            err.to_string(),
111            "Kernel error: download_column: dtoh copy failed: device error 42"
112        );
113    }
114
115    #[test]
116    fn test_execution_ctx() {
117        let err = XlogError::execution_ctx("execute_node", "filter failed", &"type mismatch");
118        assert_eq!(
119            err.to_string(),
120            "Execution error: execute_node: filter failed: type mismatch"
121        );
122    }
123
124    #[test]
125    fn test_compilation_ctx() {
126        let err = XlogError::compilation_ctx("compile_d4", "frontier overflow", &"limit 1024");
127        assert_eq!(
128            err.to_string(),
129            "Compilation error: compile_d4: frontier overflow: limit 1024"
130        );
131    }
132}