infiniloom_engine/
error.rs1use thiserror::Error;
7
8use crate::config::ConfigError;
9use crate::git::GitError;
10use crate::incremental::CacheError;
11use crate::parser::ParserError;
12use crate::remote::RemoteError;
13use crate::semantic::SemanticError;
14
15#[derive(Debug, Error)]
17pub enum InfiniloomError {
18 #[error("Parse error: {0}")]
20 Parser(#[from] ParserError),
21
22 #[error("Git error: {0}")]
24 Git(#[from] GitError),
25
26 #[error("Remote error: {0}")]
28 Remote(#[from] RemoteError),
29
30 #[error("Config error: {0}")]
32 Config(#[from] ConfigError),
33
34 #[error("Cache error: {0}")]
36 Cache(#[from] CacheError),
37
38 #[error("Semantic error: {0}")]
40 Semantic(#[from] SemanticError),
41
42 #[error("I/O error: {0}")]
44 Io(#[from] std::io::Error),
45
46 #[error("Security scan found {count} issues ({critical} critical)")]
48 SecurityIssues {
49 count: usize,
51 critical: usize,
53 },
54
55 #[error("Token budget exceeded: {used} tokens used, {budget} allowed")]
57 BudgetExceeded {
58 used: u32,
60 budget: u32,
62 },
63
64 #[error("Invalid input: {0}")]
66 InvalidInput(String),
67
68 #[error("Operation not supported: {0}")]
70 NotSupported(String),
71}
72
73pub type Result<T> = std::result::Result<T, InfiniloomError>;
75
76impl InfiniloomError {
77 pub fn security_issues(count: usize, critical: usize) -> Self {
79 Self::SecurityIssues { count, critical }
80 }
81
82 pub fn budget_exceeded(used: u32, budget: u32) -> Self {
84 Self::BudgetExceeded { used, budget }
85 }
86
87 pub fn invalid_input(msg: impl Into<String>) -> Self {
89 Self::InvalidInput(msg.into())
90 }
91
92 pub fn not_supported(msg: impl Into<String>) -> Self {
94 Self::NotSupported(msg.into())
95 }
96
97 pub fn is_recoverable(&self) -> bool {
99 matches!(
100 self,
101 Self::SecurityIssues { .. } | Self::BudgetExceeded { .. } | Self::InvalidInput(_)
102 )
103 }
104
105 pub fn is_critical(&self) -> bool {
107 matches!(self, Self::Parser(_) | Self::Git(_) | Self::Io(_))
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn test_error_display() {
117 let err = InfiniloomError::security_issues(5, 2);
118 assert_eq!(err.to_string(), "Security scan found 5 issues (2 critical)");
119
120 let err = InfiniloomError::budget_exceeded(150000, 100000);
121 assert_eq!(err.to_string(), "Token budget exceeded: 150000 tokens used, 100000 allowed");
122 }
123
124 #[test]
125 fn test_error_classification() {
126 let err = InfiniloomError::security_issues(1, 0);
127 assert!(err.is_recoverable());
128 assert!(!err.is_critical());
129
130 let err = InfiniloomError::Io(std::io::Error::new(std::io::ErrorKind::NotFound, "test"));
131 assert!(!err.is_recoverable());
132 assert!(err.is_critical());
133 }
134
135 #[test]
136 fn test_from_io_error() {
137 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
138 let err: InfiniloomError = io_err.into();
139 assert!(matches!(err, InfiniloomError::Io(_)));
140 }
141}