odin-protocol 1.0.0

The world's first standardized AI-to-AI communication infrastructure for Rust - 100% functional with 57K+ msgs/sec throughput
Documentation
//! Error types for ODIN Protocol

use std::fmt;

/// Result type alias for ODIN Protocol operations
pub type Result<T> = std::result::Result<T, OdinError>;

/// Error types for ODIN Protocol
#[derive(Debug, Clone)]
pub enum OdinError {
    /// Configuration error
    Configuration(String),
    /// Network communication error
    Network(String),
    /// Protocol-level error
    Protocol(String),
    /// Rule engine error
    Rule(String),
    /// Message handling error
    Message(String),
    /// Serialization/deserialization error
    Serialization(String),
    /// Authentication error
    Authentication(String),
    /// Timeout error
    Timeout(String),
    /// Connection error
    Connection(String),
    /// Invalid state error
    InvalidState(String),
    /// Resource not found error
    NotFound(String),
    /// Permission denied error
    PermissionDenied(String),
    /// Rate limit exceeded error
    RateLimitExceeded(String),
    /// Internal error
    Internal(String),
}

impl fmt::Display for OdinError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            OdinError::Configuration(msg) => write!(f, "Configuration error: {}", msg),
            OdinError::Network(msg) => write!(f, "Network error: {}", msg),
            OdinError::Protocol(msg) => write!(f, "Protocol error: {}", msg),
            OdinError::Rule(msg) => write!(f, "Rule error: {}", msg),
            OdinError::Message(msg) => write!(f, "Message error: {}", msg),
            OdinError::Serialization(msg) => write!(f, "Serialization error: {}", msg),
            OdinError::Authentication(msg) => write!(f, "Authentication error: {}", msg),
            OdinError::Timeout(msg) => write!(f, "Timeout error: {}", msg),
            OdinError::Connection(msg) => write!(f, "Connection error: {}", msg),
            OdinError::InvalidState(msg) => write!(f, "Invalid state error: {}", msg),
            OdinError::NotFound(msg) => write!(f, "Not found error: {}", msg),
            OdinError::PermissionDenied(msg) => write!(f, "Permission denied: {}", msg),
            OdinError::RateLimitExceeded(msg) => write!(f, "Rate limit exceeded: {}", msg),
            OdinError::Internal(msg) => write!(f, "Internal error: {}", msg),
        }
    }
}

impl std::error::Error for OdinError {}

impl From<serde_json::Error> for OdinError {
    fn from(err: serde_json::Error) -> Self {
        OdinError::Serialization(err.to_string())
    }
}

impl From<tokio::time::error::Elapsed> for OdinError {
    fn from(err: tokio::time::error::Elapsed) -> Self {
        OdinError::Timeout(err.to_string())
    }
}

impl From<std::io::Error> for OdinError {
    fn from(err: std::io::Error) -> Self {
        match err.kind() {
            std::io::ErrorKind::TimedOut => OdinError::Timeout(err.to_string()),
            std::io::ErrorKind::ConnectionRefused | 
            std::io::ErrorKind::ConnectionAborted | 
            std::io::ErrorKind::ConnectionReset => OdinError::Connection(err.to_string()),
            std::io::ErrorKind::NotFound => OdinError::NotFound(err.to_string()),
            std::io::ErrorKind::PermissionDenied => OdinError::PermissionDenied(err.to_string()),
            _ => OdinError::Internal(err.to_string()),
        }
    }
}

// Convenience constructors
impl OdinError {
    /// Create a configuration error
    pub fn config<S: Into<String>>(msg: S) -> Self {
        OdinError::Configuration(msg.into())
    }
    
    /// Create a network error
    pub fn network<S: Into<String>>(msg: S) -> Self {
        OdinError::Network(msg.into())
    }
    
    /// Create a protocol error
    pub fn protocol<S: Into<String>>(msg: S) -> Self {
        OdinError::Protocol(msg.into())
    }
    
    /// Create a rule error
    pub fn rule<S: Into<String>>(msg: S) -> Self {
        OdinError::Rule(msg.into())
    }
    
    /// Create a message error
    pub fn message<S: Into<String>>(msg: S) -> Self {
        OdinError::Message(msg.into())
    }
    
    /// Create a timeout error
    pub fn timeout<S: Into<String>>(msg: S) -> Self {
        OdinError::Timeout(msg.into())
    }
    
    /// Create an internal error
    pub fn internal<S: Into<String>>(msg: S) -> Self {
        OdinError::Internal(msg.into())
    }
    
    /// Check if error is retryable
    pub fn is_retryable(&self) -> bool {
        matches!(
            self,
            OdinError::Network(_) |
            OdinError::Timeout(_) |
            OdinError::Connection(_) |
            OdinError::RateLimitExceeded(_)
        )
    }
    
    /// Get error category
    pub fn category(&self) -> ErrorCategory {
        match self {
            OdinError::Configuration(_) => ErrorCategory::Configuration,
            OdinError::Network(_) | OdinError::Connection(_) => ErrorCategory::Network,
            OdinError::Protocol(_) => ErrorCategory::Protocol,
            OdinError::Rule(_) => ErrorCategory::Rule,
            OdinError::Message(_) => ErrorCategory::Message,
            OdinError::Serialization(_) => ErrorCategory::Serialization,
            OdinError::Authentication(_) | OdinError::PermissionDenied(_) => ErrorCategory::Security,
            OdinError::Timeout(_) => ErrorCategory::Timeout,
            OdinError::InvalidState(_) => ErrorCategory::State,
            OdinError::NotFound(_) => ErrorCategory::NotFound,
            OdinError::RateLimitExceeded(_) => ErrorCategory::RateLimit,
            OdinError::Internal(_) => ErrorCategory::Internal,
        }
    }
}

/// Error categories for classification
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorCategory {
    Configuration,
    Network,
    Protocol,
    Rule,
    Message,
    Serialization,
    Security,
    Timeout,
    State,
    NotFound,
    RateLimit,
    Internal,
}

impl fmt::Display for ErrorCategory {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ErrorCategory::Configuration => write!(f, "configuration"),
            ErrorCategory::Network => write!(f, "network"),
            ErrorCategory::Protocol => write!(f, "protocol"),
            ErrorCategory::Rule => write!(f, "rule"),
            ErrorCategory::Message => write!(f, "message"),
            ErrorCategory::Serialization => write!(f, "serialization"),
            ErrorCategory::Security => write!(f, "security"),
            ErrorCategory::Timeout => write!(f, "timeout"),
            ErrorCategory::State => write!(f, "state"),
            ErrorCategory::NotFound => write!(f, "not_found"),
            ErrorCategory::RateLimit => write!(f, "rate_limit"),
            ErrorCategory::Internal => write!(f, "internal"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_error_display() {
        let error = OdinError::Configuration("Invalid config".to_string());
        assert_eq!(error.to_string(), "Configuration error: Invalid config");
    }
    
    #[test]
    fn test_error_category() {
        let error = OdinError::Network("Connection failed".to_string());
        assert_eq!(error.category(), ErrorCategory::Network);
    }
    
    #[test]
    fn test_error_retryable() {
        let network_error = OdinError::Network("Temporary failure".to_string());
        assert!(network_error.is_retryable());
        
        let config_error = OdinError::Configuration("Invalid setting".to_string());
        assert!(!config_error.is_retryable());
    }
    
    #[test]
    fn test_error_constructors() {
        let error = OdinError::config("test");
        assert!(matches!(error, OdinError::Configuration(_)));
        
        let error = OdinError::network("test");
        assert!(matches!(error, OdinError::Network(_)));
        
        let error = OdinError::timeout("test");
        assert!(matches!(error, OdinError::Timeout(_)));
    }
    
    #[test]
    fn test_from_serde_error() {
        let json_error = serde_json::from_str::<i32>("invalid json").unwrap_err();
        let odin_error: OdinError = json_error.into();
        assert!(matches!(odin_error, OdinError::Serialization(_)));
    }
}