Skip to main content

legion_protocol/
error.rs

1//! Error types for the Legion Protocol library
2
3use thiserror::Error;
4
5/// The main error type for Legion Protocol operations
6#[derive(Error, Debug, Clone, PartialEq)]
7pub enum IronError {
8    /// Parse error when processing IRC messages or protocol data
9    #[error("Parse error: {0}")]
10    Parse(String),
11
12    /// Security violation detected
13    #[error("Security violation: {0}")]
14    SecurityViolation(String),
15
16    /// Authentication failure
17    #[error("Authentication failed: {0}")]
18    Auth(String),
19
20    /// Connection error
21    #[error("Connection error: {0}")]
22    Connection(String),
23
24    /// Protocol violation
25    #[error("Protocol violation: {0}")]
26    Protocol(String),
27
28    /// Rate limiting violation
29    #[error("Rate limit exceeded: {0}")]
30    RateLimit(String),
31
32    /// Configuration error
33    #[error("Configuration error: {0}")]
34    Config(String),
35
36    /// Capability negotiation error
37    #[error("Capability error: {0}")]
38    Capability(String),
39
40    /// SASL authentication error
41    #[error("SASL error: {0}")]
42    Sasl(String),
43
44    /// I/O error
45    #[error("I/O error: {0}")]
46    Io(String),
47
48    /// Timeout error
49    #[error("Timeout: {0}")]
50    Timeout(String),
51
52    /// Invalid input
53    #[error("Invalid input: {0}")]
54    InvalidInput(String),
55
56    /// Feature not supported
57    #[error("Feature not supported: {0}")]
58    NotSupported(String),
59
60    /// Internal error
61    #[error("Internal error: {0}")]
62    Internal(String),
63}
64
65/// A specialized Result type for Iron Protocol operations
66pub type Result<T> = std::result::Result<T, IronError>;
67
68impl From<std::io::Error> for IronError {
69    fn from(err: std::io::Error) -> Self {
70        IronError::Io(err.to_string())
71    }
72}
73
74#[cfg(feature = "serde")]
75impl From<serde_json::Error> for IronError {
76    fn from(err: serde_json::Error) -> Self {
77        IronError::Parse(format!("JSON parse error: {}", err))
78    }
79}
80
81impl IronError {
82    /// Returns true if this error indicates a security violation
83    pub fn is_security_violation(&self) -> bool {
84        matches!(self, IronError::SecurityViolation(_))
85    }
86
87    /// Returns true if this error is recoverable
88    pub fn is_recoverable(&self) -> bool {
89        match self {
90            IronError::Parse(_) |
91            IronError::Protocol(_) |
92            IronError::RateLimit(_) |
93            IronError::Timeout(_) |
94            IronError::InvalidInput(_) => true,
95            
96            IronError::SecurityViolation(_) |
97            IronError::Auth(_) |
98            IronError::Connection(_) |
99            IronError::Config(_) |
100            IronError::Capability(_) |
101            IronError::Sasl(_) |
102            IronError::Io(_) |
103            IronError::NotSupported(_) |
104            IronError::Internal(_) => false,
105        }
106    }
107
108    /// Returns the error category
109    pub fn category(&self) -> &'static str {
110        match self {
111            IronError::Parse(_) => "parse",
112            IronError::SecurityViolation(_) => "security",
113            IronError::Auth(_) => "auth",
114            IronError::Connection(_) => "connection",
115            IronError::Protocol(_) => "protocol",
116            IronError::RateLimit(_) => "rate_limit",
117            IronError::Config(_) => "config",
118            IronError::Capability(_) => "capability",
119            IronError::Sasl(_) => "sasl",
120            IronError::Io(_) => "io",
121            IronError::Timeout(_) => "timeout",
122            IronError::InvalidInput(_) => "invalid_input",
123            IronError::NotSupported(_) => "not_supported",
124            IronError::Internal(_) => "internal",
125        }
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn test_error_categories() {
135        assert_eq!(IronError::Parse("test".to_string()).category(), "parse");
136        assert_eq!(IronError::SecurityViolation("test".to_string()).category(), "security");
137        assert_eq!(IronError::Auth("test".to_string()).category(), "auth");
138    }
139
140    #[test]
141    fn test_security_violation_detection() {
142        assert!(IronError::SecurityViolation("test".to_string()).is_security_violation());
143        assert!(!IronError::Parse("test".to_string()).is_security_violation());
144    }
145
146    #[test]
147    fn test_recoverable_errors() {
148        assert!(IronError::Parse("test".to_string()).is_recoverable());
149        assert!(IronError::Protocol("test".to_string()).is_recoverable());
150        assert!(!IronError::SecurityViolation("test".to_string()).is_recoverable());
151        assert!(!IronError::Auth("test".to_string()).is_recoverable());
152    }
153
154    #[test]
155    fn test_io_error_conversion() {
156        let io_err = std::io::Error::new(std::io::ErrorKind::BrokenPipe, "test");
157        let iron_err: IronError = io_err.into();
158        assert!(matches!(iron_err, IronError::Io(_)));
159    }
160}