1use thiserror::Error;
4
5#[derive(Debug, Error)]
7#[non_exhaustive]
8pub enum XlogError {
9 #[error("Parse error: {0}")]
11 Parse(String),
12
13 #[error("Stratification failed: cycle through negation involving {0:?}")]
15 StratificationCycle(Vec<String>),
16
17 #[error("Domain safety: variable {0} not bound in positive literal")]
19 UnsafeVariable(String),
20
21 #[error("Resource exhausted: {context}, estimated {estimated_bytes} bytes, budget {budget_bytes} bytes")]
23 ResourceExhausted {
24 context: String,
26 estimated_bytes: u64,
28 budget_bytes: u64,
30 },
31
32 #[error("Kernel error: {0}")]
34 Kernel(String),
35
36 #[error("Type error: {0}")]
38 Type(String),
39
40 #[error("Compilation error: {0}")]
42 Compilation(String),
43
44 #[error("Unsupported epistemic construct: {construct} ({context})")]
46 UnsupportedEpistemicConstruct {
47 construct: String,
49 context: String,
51 },
52
53 #[error("Execution error: {0}")]
55 Execution(String),
56}
57
58impl XlogError {
59 pub fn kernel_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
61 XlogError::Kernel(format!("{op}: {detail}: {source}"))
62 }
63
64 pub fn execution_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
66 XlogError::Execution(format!("{op}: {detail}: {source}"))
67 }
68
69 pub fn compilation_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
71 XlogError::Compilation(format!("{op}: {detail}: {source}"))
72 }
73}
74
75pub 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}