odin_protocol/
error.rs

1//! Error types for ODIN Protocol
2
3use std::fmt;
4
5/// Result type alias for ODIN Protocol operations
6pub type Result<T> = std::result::Result<T, OdinError>;
7
8/// Error types for ODIN Protocol
9#[derive(Debug, Clone)]
10pub enum OdinError {
11    /// Configuration error
12    Configuration(String),
13    /// Network communication error
14    Network(String),
15    /// Protocol-level error
16    Protocol(String),
17    /// Rule engine error
18    Rule(String),
19    /// Message handling error
20    Message(String),
21    /// Serialization/deserialization error
22    Serialization(String),
23    /// Authentication error
24    Authentication(String),
25    /// Timeout error
26    Timeout(String),
27    /// Connection error
28    Connection(String),
29    /// Invalid state error
30    InvalidState(String),
31    /// Resource not found error
32    NotFound(String),
33    /// Permission denied error
34    PermissionDenied(String),
35    /// Rate limit exceeded error
36    RateLimitExceeded(String),
37    /// Internal error
38    Internal(String),
39}
40
41impl fmt::Display for OdinError {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            OdinError::Configuration(msg) => write!(f, "Configuration error: {}", msg),
45            OdinError::Network(msg) => write!(f, "Network error: {}", msg),
46            OdinError::Protocol(msg) => write!(f, "Protocol error: {}", msg),
47            OdinError::Rule(msg) => write!(f, "Rule error: {}", msg),
48            OdinError::Message(msg) => write!(f, "Message error: {}", msg),
49            OdinError::Serialization(msg) => write!(f, "Serialization error: {}", msg),
50            OdinError::Authentication(msg) => write!(f, "Authentication error: {}", msg),
51            OdinError::Timeout(msg) => write!(f, "Timeout error: {}", msg),
52            OdinError::Connection(msg) => write!(f, "Connection error: {}", msg),
53            OdinError::InvalidState(msg) => write!(f, "Invalid state error: {}", msg),
54            OdinError::NotFound(msg) => write!(f, "Not found error: {}", msg),
55            OdinError::PermissionDenied(msg) => write!(f, "Permission denied: {}", msg),
56            OdinError::RateLimitExceeded(msg) => write!(f, "Rate limit exceeded: {}", msg),
57            OdinError::Internal(msg) => write!(f, "Internal error: {}", msg),
58        }
59    }
60}
61
62impl std::error::Error for OdinError {}
63
64impl From<serde_json::Error> for OdinError {
65    fn from(err: serde_json::Error) -> Self {
66        OdinError::Serialization(err.to_string())
67    }
68}
69
70impl From<tokio::time::error::Elapsed> for OdinError {
71    fn from(err: tokio::time::error::Elapsed) -> Self {
72        OdinError::Timeout(err.to_string())
73    }
74}
75
76impl From<std::io::Error> for OdinError {
77    fn from(err: std::io::Error) -> Self {
78        match err.kind() {
79            std::io::ErrorKind::TimedOut => OdinError::Timeout(err.to_string()),
80            std::io::ErrorKind::ConnectionRefused | 
81            std::io::ErrorKind::ConnectionAborted | 
82            std::io::ErrorKind::ConnectionReset => OdinError::Connection(err.to_string()),
83            std::io::ErrorKind::NotFound => OdinError::NotFound(err.to_string()),
84            std::io::ErrorKind::PermissionDenied => OdinError::PermissionDenied(err.to_string()),
85            _ => OdinError::Internal(err.to_string()),
86        }
87    }
88}
89
90// Convenience constructors
91impl OdinError {
92    /// Create a configuration error
93    pub fn config<S: Into<String>>(msg: S) -> Self {
94        OdinError::Configuration(msg.into())
95    }
96    
97    /// Create a network error
98    pub fn network<S: Into<String>>(msg: S) -> Self {
99        OdinError::Network(msg.into())
100    }
101    
102    /// Create a protocol error
103    pub fn protocol<S: Into<String>>(msg: S) -> Self {
104        OdinError::Protocol(msg.into())
105    }
106    
107    /// Create a rule error
108    pub fn rule<S: Into<String>>(msg: S) -> Self {
109        OdinError::Rule(msg.into())
110    }
111    
112    /// Create a message error
113    pub fn message<S: Into<String>>(msg: S) -> Self {
114        OdinError::Message(msg.into())
115    }
116    
117    /// Create a timeout error
118    pub fn timeout<S: Into<String>>(msg: S) -> Self {
119        OdinError::Timeout(msg.into())
120    }
121    
122    /// Create an internal error
123    pub fn internal<S: Into<String>>(msg: S) -> Self {
124        OdinError::Internal(msg.into())
125    }
126    
127    /// Check if error is retryable
128    pub fn is_retryable(&self) -> bool {
129        matches!(
130            self,
131            OdinError::Network(_) |
132            OdinError::Timeout(_) |
133            OdinError::Connection(_) |
134            OdinError::RateLimitExceeded(_)
135        )
136    }
137    
138    /// Get error category
139    pub fn category(&self) -> ErrorCategory {
140        match self {
141            OdinError::Configuration(_) => ErrorCategory::Configuration,
142            OdinError::Network(_) | OdinError::Connection(_) => ErrorCategory::Network,
143            OdinError::Protocol(_) => ErrorCategory::Protocol,
144            OdinError::Rule(_) => ErrorCategory::Rule,
145            OdinError::Message(_) => ErrorCategory::Message,
146            OdinError::Serialization(_) => ErrorCategory::Serialization,
147            OdinError::Authentication(_) | OdinError::PermissionDenied(_) => ErrorCategory::Security,
148            OdinError::Timeout(_) => ErrorCategory::Timeout,
149            OdinError::InvalidState(_) => ErrorCategory::State,
150            OdinError::NotFound(_) => ErrorCategory::NotFound,
151            OdinError::RateLimitExceeded(_) => ErrorCategory::RateLimit,
152            OdinError::Internal(_) => ErrorCategory::Internal,
153        }
154    }
155}
156
157/// Error categories for classification
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159pub enum ErrorCategory {
160    Configuration,
161    Network,
162    Protocol,
163    Rule,
164    Message,
165    Serialization,
166    Security,
167    Timeout,
168    State,
169    NotFound,
170    RateLimit,
171    Internal,
172}
173
174impl fmt::Display for ErrorCategory {
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        match self {
177            ErrorCategory::Configuration => write!(f, "configuration"),
178            ErrorCategory::Network => write!(f, "network"),
179            ErrorCategory::Protocol => write!(f, "protocol"),
180            ErrorCategory::Rule => write!(f, "rule"),
181            ErrorCategory::Message => write!(f, "message"),
182            ErrorCategory::Serialization => write!(f, "serialization"),
183            ErrorCategory::Security => write!(f, "security"),
184            ErrorCategory::Timeout => write!(f, "timeout"),
185            ErrorCategory::State => write!(f, "state"),
186            ErrorCategory::NotFound => write!(f, "not_found"),
187            ErrorCategory::RateLimit => write!(f, "rate_limit"),
188            ErrorCategory::Internal => write!(f, "internal"),
189        }
190    }
191}
192
193#[cfg(test)]
194mod tests {
195    use super::*;
196    
197    #[test]
198    fn test_error_display() {
199        let error = OdinError::Configuration("Invalid config".to_string());
200        assert_eq!(error.to_string(), "Configuration error: Invalid config");
201    }
202    
203    #[test]
204    fn test_error_category() {
205        let error = OdinError::Network("Connection failed".to_string());
206        assert_eq!(error.category(), ErrorCategory::Network);
207    }
208    
209    #[test]
210    fn test_error_retryable() {
211        let network_error = OdinError::Network("Temporary failure".to_string());
212        assert!(network_error.is_retryable());
213        
214        let config_error = OdinError::Configuration("Invalid setting".to_string());
215        assert!(!config_error.is_retryable());
216    }
217    
218    #[test]
219    fn test_error_constructors() {
220        let error = OdinError::config("test");
221        assert!(matches!(error, OdinError::Configuration(_)));
222        
223        let error = OdinError::network("test");
224        assert!(matches!(error, OdinError::Network(_)));
225        
226        let error = OdinError::timeout("test");
227        assert!(matches!(error, OdinError::Timeout(_)));
228    }
229    
230    #[test]
231    fn test_from_serde_error() {
232        let json_error = serde_json::from_str::<i32>("invalid json").unwrap_err();
233        let odin_error: OdinError = json_error.into();
234        assert!(matches!(odin_error, OdinError::Serialization(_)));
235    }
236}