zero-trust-sdk 0.1.0

Rust SDK for Zero Trust Blockchain Database - Secure, programmable access to zero-trust data storage
Documentation
//! Error types for the Zero Trust SDK

use thiserror::Error;

/// Result type alias for Zero Trust SDK operations
pub type Result<T> = std::result::Result<T, ZeroTrustError>;

/// Main error type for the Zero Trust SDK
#[derive(Error, Debug)]
pub enum ZeroTrustError {
    /// HTTP request errors
    #[error("API request failed: {0}")]
    ApiError(#[from] reqwest::Error),
    
    /// JSON serialization/deserialization errors
    #[error("Serialization error: {0}")]
    SerializationError(#[from] serde_json::Error),
    
    /// IO errors
    #[error("IO error: {0}")]
    IoError(#[from] std::io::Error),
    
    /// Database errors (when migration feature is enabled)
    #[cfg(feature = "migration")]
    #[error("Database error: {0}")]
    DatabaseError(#[from] sqlx::Error),
    
    /// Configuration errors
    #[error("Configuration error: {0}")]
    ConfigError(String),
    
    /// Authentication errors
    #[error("Authentication failed: {0}")]
    AuthError(String),
    
    /// Validation errors
    #[error("Validation error: {0}")]
    ValidationError(String),
    
    /// Migration errors
    #[cfg(feature = "migration")]
    #[error("Migration error: {0}")]
    MigrationError(String),
    
    /// Sync errors
    #[cfg(feature = "sync")]
    #[error("Sync error: {0}")]
    SyncError(String),
    
    /// Network timeout
    #[error("Request timed out")]
    Timeout,
    
    /// Server errors (5xx)
    #[error("Server error: {status} - {message}")]
    ServerError {
        /// HTTP status code
        status: u16,
        /// Error message
        message: String,
    },
    
    /// Client errors (4xx)
    #[error("Client error: {status} - {message}")]
    ClientError {
        /// HTTP status code
        status: u16,
        /// Error message
        message: String,
    },
    
    /// Resource not found
    #[error("Resource not found: {resource}")]
    NotFound {
        /// Resource identifier
        resource: String,
    },
    
    /// Permission denied
    #[error("Permission denied: {operation}")]
    PermissionDenied {
        /// Operation that was denied
        operation: String,
    },
    
    /// Rate limit exceeded
    #[error("Rate limit exceeded. Try again in {retry_after} seconds")]
    RateLimitExceeded {
        /// Seconds to wait before retrying
        retry_after: u64,
    },
    
    /// Generic error
    #[error("{0}")]
    Generic(String),
}

impl ZeroTrustError {
    /// Create a new configuration error
    pub fn config<S: Into<String>>(message: S) -> Self {
        Self::ConfigError(message.into())
    }
    
    /// Create a new authentication error
    pub fn auth<S: Into<String>>(message: S) -> Self {
        Self::AuthError(message.into())
    }
    
    /// Create a new validation error
    pub fn validation<S: Into<String>>(message: S) -> Self {
        Self::ValidationError(message.into())
    }
    
    /// Create a new generic error
    pub fn generic<S: Into<String>>(message: S) -> Self {
        Self::Generic(message.into())
    }
    
    /// Create a new not found error
    pub fn not_found<S: Into<String>>(resource: S) -> Self {
        Self::NotFound {
            resource: resource.into(),
        }
    }
    
    /// Create a new permission denied error
    pub fn permission_denied<S: Into<String>>(operation: S) -> Self {
        Self::PermissionDenied {
            operation: operation.into(),
        }
    }
    
    /// Create a server error from HTTP status and message
    pub fn server_error(status: u16, message: String) -> Self {
        Self::ServerError { status, message }
    }
    
    /// Create a client error from HTTP status and message
    pub fn client_error(status: u16, message: String) -> Self {
        Self::ClientError { status, message }
    }
    
    /// Create a rate limit error
    pub fn rate_limit(retry_after: u64) -> Self {
        Self::RateLimitExceeded { retry_after }
    }
    
    /// Check if this is a retryable error
    pub fn is_retryable(&self) -> bool {
        match self {
            Self::ApiError(e) => e.is_timeout() || e.is_connect(),
            Self::ServerError { status, .. } => *status >= 500,
            Self::Timeout => true,
            Self::RateLimitExceeded { .. } => true,
            _ => false,
        }
    }
    
    /// Check if this is an authentication error
    pub fn is_auth_error(&self) -> bool {
        matches!(self, Self::AuthError(_) | Self::PermissionDenied { .. })
    }
    
    /// Check if this is a client error (user's fault)
    pub fn is_client_error(&self) -> bool {
        matches!(
            self,
            Self::ValidationError(_)
                | Self::ConfigError(_)
                | Self::ClientError { .. }
                | Self::NotFound { .. }
                | Self::PermissionDenied { .. }
        )
    }
}

impl From<anyhow::Error> for ZeroTrustError {
    fn from(err: anyhow::Error) -> Self {
        Self::Generic(err.to_string())
    }
}

impl From<base64::DecodeError> for ZeroTrustError {
    fn from(err: base64::DecodeError) -> Self {
        Self::Generic(format!("Base64 decode error: {}", err))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_error_creation() {
        let err = ZeroTrustError::auth("Invalid credentials");
        assert!(err.is_auth_error());
        assert!(!err.is_retryable());
        
        let err = ZeroTrustError::server_error(500, "Internal error".to_string());
        assert!(err.is_retryable());
        assert!(!err.is_client_error());
        
        let err = ZeroTrustError::validation("Invalid input");
        assert!(err.is_client_error());
        assert!(!err.is_retryable());
    }
}