1use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum XlogError {
8 #[error("Parse error: {0}")]
9 Parse(String),
10
11 #[error("Stratification failed: cycle through negation involving {0:?}")]
12 StratificationCycle(Vec<String>),
13
14 #[error("Domain safety: variable {0} not bound in positive literal")]
15 UnsafeVariable(String),
16
17 #[error("Resource exhausted: {context}, estimated {estimated_bytes} bytes, budget {budget_bytes} bytes")]
18 ResourceExhausted {
19 context: String,
20 estimated_bytes: u64,
21 budget_bytes: u64,
22 },
23
24 #[error("Kernel error: {0}")]
25 Kernel(String),
26
27 #[error("Type error: {0}")]
28 Type(String),
29
30 #[error("Compilation error: {0}")]
31 Compilation(String),
32
33 #[error("Execution error: {0}")]
34 Execution(String),
35}
36
37impl XlogError {
38 pub fn kernel_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
40 XlogError::Kernel(format!("{op}: {detail}: {source}"))
41 }
42
43 pub fn execution_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
45 XlogError::Execution(format!("{op}: {detail}: {source}"))
46 }
47
48 pub fn compilation_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
50 XlogError::Compilation(format!("{op}: {detail}: {source}"))
51 }
52}
53
54pub type Result<T> = std::result::Result<T, XlogError>;
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn test_parse_error_display() {
63 let err = XlogError::Parse("unexpected token".to_string());
64 assert_eq!(err.to_string(), "Parse error: unexpected token");
65 }
66
67 #[test]
68 fn test_stratification_cycle_display() {
69 let err = XlogError::StratificationCycle(vec!["foo".to_string(), "bar".to_string()]);
70 assert!(err.to_string().contains("foo"));
71 assert!(err.to_string().contains("bar"));
72 }
73
74 #[test]
75 fn test_resource_exhausted_display() {
76 let err = XlogError::ResourceExhausted {
77 context: "join operation".to_string(),
78 estimated_bytes: 1024,
79 budget_bytes: 512,
80 };
81 assert!(err.to_string().contains("1024"));
82 assert!(err.to_string().contains("512"));
83 }
84
85 #[test]
86 fn test_kernel_ctx() {
87 let err = XlogError::kernel_ctx("download_column", "dtoh copy failed", &"device error 42");
88 assert_eq!(
89 err.to_string(),
90 "Kernel error: download_column: dtoh copy failed: device error 42"
91 );
92 }
93
94 #[test]
95 fn test_execution_ctx() {
96 let err = XlogError::execution_ctx("execute_node", "filter failed", &"type mismatch");
97 assert_eq!(
98 err.to_string(),
99 "Execution error: execute_node: filter failed: type mismatch"
100 );
101 }
102
103 #[test]
104 fn test_compilation_ctx() {
105 let err = XlogError::compilation_ctx("compile_d4", "frontier overflow", &"limit 1024");
106 assert_eq!(
107 err.to_string(),
108 "Compilation error: compile_d4: frontier overflow: limit 1024"
109 );
110 }
111}