use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum CoreError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("YAML parsing error: {0}")]
Yaml(#[from] serde_yaml::Error),
#[error("JSON parsing error: {0}")]
Json(#[from] serde_json::Error),
#[error("Validation error: {message}")]
Validation { message: String },
#[error("Configuration error: {message}")]
Configuration { message: String },
#[error("Service not found: {service_type}")]
ServiceNotFound { service_type: String },
#[error("Invalid service scope: {scope}")]
InvalidServiceScope { scope: String },
#[error("Lock error on resource: {resource}")]
LockError { resource: String },
#[error("Lifecycle error in component '{component}' during '{operation}': {source}")]
LifecycleError {
component: String,
operation: String,
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("System error: {message}")]
SystemError {
message: String,
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("Module error: {message}")]
Module { message: String },
#[error("Provider error: {message}")]
Provider { message: String },
#[error("Codegen error: {message}")]
Codegen { message: String },
#[error("Template error: {message}")]
Template { message: String },
#[error("Database error: {message}")]
Database { message: String },
#[error("Circular dependency detected: {path} (cycle at: {cycle_service})")]
CircularDependency { path: String, cycle_service: String },
#[error("Invalid service descriptor: {message}")]
InvalidServiceDescriptor { message: String },
#[error("Dependency resolution failed for '{service_type}': {message}")]
DependencyResolutionFailed {
service_type: String,
message: String,
},
#[error("API error: {code} - {message}")]
Api {
code: String,
message: String,
hint: Option<String>,
},
#[error("Service initialization failed for '{service_type}': {source}")]
ServiceInitializationFailed {
service_type: String,
source: Box<dyn std::error::Error + Send + Sync>,
},
}
impl CoreError {
pub fn validation(message: impl Into<String>) -> Self {
Self::Validation {
message: message.into(),
}
}
pub fn configuration(message: impl Into<String>) -> Self {
Self::Configuration {
message: message.into(),
}
}
pub fn service_not_found(service_type: impl Into<String>) -> Self {
Self::ServiceNotFound {
service_type: service_type.into(),
}
}
pub fn system_error(message: impl Into<String>) -> Self {
Self::SystemError {
message: message.into(),
source: None,
}
}
pub fn system_error_with_source(
message: impl Into<String>,
source: Box<dyn std::error::Error + Send + Sync>,
) -> Self {
Self::SystemError {
message: message.into(),
source: Some(source),
}
}
pub fn api_error(code: impl Into<String>, message: impl Into<String>) -> Self {
Self::Api {
code: code.into(),
message: message.into(),
hint: None,
}
}
pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
if let Self::Api {
hint: ref mut h, ..
} = self
{
*h = Some(hint.into());
}
self
}
pub fn is_validation(&self) -> bool {
matches!(self, Self::Validation { .. })
}
pub fn is_configuration(&self) -> bool {
matches!(self, Self::Configuration { .. })
}
pub fn is_service(&self) -> bool {
matches!(self, Self::ServiceNotFound { .. })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorDefinition {
pub code: String,
pub http: u16,
pub message: String,
pub hint: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiErrorResponse {
pub error: ApiError,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiError {
pub code: String,
pub message: String,
pub hint: Option<String>,
}
impl ApiError {
pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
Self {
code: code.into(),
message: message.into(),
hint: None,
}
}
pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
self.hint = Some(hint.into());
self
}
}
impl From<CoreError> for ApiError {
fn from(error: CoreError) -> Self {
match error {
CoreError::Api {
code,
message,
hint,
} => Self {
code,
message,
hint,
},
CoreError::Validation { message } => Self::new("VALIDATION_ERROR", message),
CoreError::Configuration { message } => Self::new("CONFIG_ERROR", message),
CoreError::ServiceNotFound { service_type } => Self::new(
"SERVICE_NOT_FOUND",
format!("Service not found: {}", service_type),
),
_ => Self::new("INTERNAL_ERROR", error.to_string()),
}
}
}
impl From<ApiError> for ApiErrorResponse {
fn from(error: ApiError) -> Self {
Self { error }
}
}
pub type ErrorCatalog = HashMap<String, ErrorDefinition>;
pub type ElifError = CoreError;