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("D4 compile declined: {context}: {detail}")]
39 CompileCapacityExceeded {
40 context: String,
42 detail: String,
44 },
45
46 #[error("D4 equivalence verify declined: {context}: {detail}")]
54 VerifyBudgetExceeded {
55 context: String,
57 detail: String,
59 },
60
61 #[error("Kernel error: {0}")]
63 Kernel(String),
64
65 #[error("Type error: {0}")]
67 Type(String),
68
69 #[error("Compilation error: {0}")]
71 Compilation(String),
72
73 #[error("Unsupported epistemic construct: {construct} ({context})")]
75 UnsupportedEpistemicConstruct {
76 construct: String,
78 context: String,
80 },
81
82 #[error("Execution error: {0}")]
84 Execution(String),
85}
86
87impl XlogError {
88 pub fn kernel_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
90 XlogError::Kernel(format!("{op}: {detail}: {source}"))
91 }
92
93 pub fn execution_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
95 XlogError::Execution(format!("{op}: {detail}: {source}"))
96 }
97
98 pub fn compilation_ctx(op: &str, detail: &str, source: &impl std::fmt::Display) -> Self {
100 XlogError::Compilation(format!("{op}: {detail}: {source}"))
101 }
102}
103
104pub type Result<T> = std::result::Result<T, XlogError>;
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_parse_error_display() {
113 let err = XlogError::Parse("unexpected token".to_string());
114 assert_eq!(err.to_string(), "Parse error: unexpected token");
115 }
116
117 #[test]
118 fn test_stratification_cycle_display() {
119 let err = XlogError::StratificationCycle(vec!["foo".to_string(), "bar".to_string()]);
120 assert!(err.to_string().contains("foo"));
121 assert!(err.to_string().contains("bar"));
122 }
123
124 #[test]
125 fn test_resource_exhausted_display() {
126 let err = XlogError::ResourceExhausted {
127 context: "join operation".to_string(),
128 estimated_bytes: 1024,
129 budget_bytes: 512,
130 };
131 assert!(err.to_string().contains("1024"));
132 assert!(err.to_string().contains("512"));
133 }
134
135 #[test]
136 fn test_kernel_ctx() {
137 let err = XlogError::kernel_ctx("download_column", "dtoh copy failed", &"device error 42");
138 assert_eq!(
139 err.to_string(),
140 "Kernel error: download_column: dtoh copy failed: device error 42"
141 );
142 }
143
144 #[test]
145 fn test_execution_ctx() {
146 let err = XlogError::execution_ctx("execute_node", "filter failed", &"type mismatch");
147 assert_eq!(
148 err.to_string(),
149 "Execution error: execute_node: filter failed: type mismatch"
150 );
151 }
152
153 #[test]
154 fn test_compilation_ctx() {
155 let err = XlogError::compilation_ctx("compile_d4", "frontier overflow", &"limit 1024");
156 assert_eq!(
157 err.to_string(),
158 "Compilation error: compile_d4: frontier overflow: limit 1024"
159 );
160 }
161}