use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum VtxError {
DatabaseError(String),
SerializationError(String),
AuthDenied(u16),
PermissionDenied(String),
NotFound(String),
Internal(String),
}
impl VtxError {
pub fn from_host_message(message: impl Into<String>) -> Self {
let msg = message.into();
let lower = msg.to_lowercase();
if lower.contains("permission denied") {
return VtxError::PermissionDenied(msg);
}
if lower.contains("uuid not found") || lower.contains("not found") {
return VtxError::NotFound(msg);
}
VtxError::Internal(msg)
}
}
impl fmt::Display for VtxError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VtxError::DatabaseError(msg) => write!(f, "Database error: {}", msg),
VtxError::SerializationError(msg) => write!(f, "Data serialization error: {}", msg),
VtxError::AuthDenied(code) => write!(f, "Authentication denied (Code: {})", code),
VtxError::PermissionDenied(msg) => write!(f, "Permission denied: {}", msg),
VtxError::NotFound(msg) => write!(f, "Resource not found: {}", msg),
VtxError::Internal(msg) => write!(f, "Internal error: {}", msg),
}
}
}
impl std::error::Error for VtxError {}
pub type Error = VtxError;
pub type VtxResult<T> = std::result::Result<T, VtxError>;
pub type Result<T> = VtxResult<T>;
#[cfg(test)]
mod tests {
use super::VtxError;
#[test]
fn from_host_message_maps_permission_denied() {
let err = VtxError::from_host_message("Permission denied: read only");
match err {
VtxError::PermissionDenied(msg) => {
assert!(msg.contains("Permission denied"));
}
_ => panic!("expected PermissionDenied"),
}
}
#[test]
fn from_host_message_maps_not_found() {
let err = VtxError::from_host_message("UUID not found: 1234");
match err {
VtxError::NotFound(msg) => {
assert!(msg.contains("not found"));
}
_ => panic!("expected NotFound"),
}
}
#[test]
fn from_host_message_defaults_to_internal() {
let err = VtxError::from_host_message("something unexpected");
match err {
VtxError::Internal(msg) => {
assert!(msg.contains("unexpected"));
}
_ => panic!("expected Internal"),
}
}
#[test]
fn display_formats_errors() {
let err = VtxError::AuthDenied(401);
assert_eq!(err.to_string(), "Authentication denied (Code: 401)");
let err = VtxError::DatabaseError("boom".to_string());
assert_eq!(err.to_string(), "Database error: boom");
}
}