use std::fmt;
#[derive(Debug, Clone)]
pub enum PerKeyError {
NotFound,
PermissionDenied(String),
Unknown { message: String },
}
impl fmt::Display for PerKeyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PerKeyError::NotFound => write!(f, "not found"),
PerKeyError::PermissionDenied(msg) => write!(f, "permission denied: {msg}"),
PerKeyError::Unknown { message } => write!(f, "unknown: {message}"),
}
}
}
#[derive(Debug, Clone)]
pub struct KeyError {
pub key: String,
pub error: PerKeyError,
}
#[derive(Debug, Clone)]
pub struct BatchError {
pub succeeded: Vec<String>,
pub errors: Vec<KeyError>,
}
impl BatchError {
pub fn total_count(&self) -> usize {
self.succeeded.len() + self.errors.len()
}
pub fn failed_count(&self) -> usize {
self.errors.len()
}
}
impl fmt::Display for BatchError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"batch operation failed: {} keys failed ({} succeeded, {} total)",
self.failed_count(),
self.succeeded.len(),
self.total_count(),
)
}
}
impl std::error::Error for BatchError {}
#[derive(Debug, thiserror::Error)]
pub enum BlobStorageError {
#[error("blob not found: {0}")]
NotFound(String),
#[error("blob already exists: {0}")]
AlreadyExists(String),
#[error("operation not supported: {0}")]
NotSupported(String),
#[error("backend misconfigured: {0}")]
BackendMisconfigured(String),
#[error("invalid input: {0}")]
InvalidInput(String),
#[error("storage error: {message}")]
Storage {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
},
#[error("encryption error: {message}")]
Encryption {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
},
#[error("permission denied: {0}")]
PermissionDenied(String),
#[error("batch error: {0}")]
Batch(#[from] BatchError),
}
pub type Result<T> = std::result::Result<T, BlobStorageError>;
impl From<std::io::Error> for BlobStorageError {
fn from(e: std::io::Error) -> Self {
Self::Storage {
message: "I/O error".to_string(),
source: Some(Box::new(e)),
}
}
}
impl From<String> for BlobStorageError {
fn from(msg: String) -> Self {
Self::Storage {
message: msg,
source: None,
}
}
}
impl From<&str> for BlobStorageError {
fn from(msg: &str) -> Self {
Self::Storage {
message: msg.to_string(),
source: None,
}
}
}
impl From<xtax_encryption::EncryptionError> for BlobStorageError {
fn from(e: xtax_encryption::EncryptionError) -> Self {
Self::Encryption {
message: e.to_string(),
source: Some(Box::new(e)),
}
}
}