elif_core/errors/
core.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use thiserror::Error;
4
5/// Core error type for the elif framework
6#[derive(Debug, Error)]
7pub enum CoreError {
8    #[error("IO error: {0}")]
9    Io(#[from] std::io::Error),
10
11    #[error("YAML parsing error: {0}")]
12    Yaml(#[from] serde_yaml::Error),
13
14    #[error("JSON parsing error: {0}")]
15    Json(#[from] serde_json::Error),
16
17    #[error("Validation error: {message}")]
18    Validation { message: String },
19
20    #[error("Configuration error: {message}")]
21    Configuration { message: String },
22
23    #[error("Service not found: {service_type}")]
24    ServiceNotFound { service_type: String },
25
26    #[error("Invalid service scope: {scope}")]
27    InvalidServiceScope { scope: String },
28
29    #[error("Lock error on resource: {resource}")]
30    LockError { resource: String },
31
32    #[error("Lifecycle error in component '{component}' during '{operation}': {source}")]
33    LifecycleError {
34        component: String,
35        operation: String,
36        source: Box<dyn std::error::Error + Send + Sync>,
37    },
38
39    #[error("System error: {message}")]
40    SystemError {
41        message: String,
42        source: Option<Box<dyn std::error::Error + Send + Sync>>,
43    },
44
45    #[error("Module error: {message}")]
46    Module { message: String },
47
48    #[error("Provider error: {message}")]
49    Provider { message: String },
50
51    #[error("Codegen error: {message}")]
52    Codegen { message: String },
53
54    #[error("Template error: {message}")]
55    Template { message: String },
56
57    #[error("Database error: {message}")]
58    Database { message: String },
59
60    #[error("Circular dependency detected: {path} (cycle at: {cycle_service})")]
61    CircularDependency { path: String, cycle_service: String },
62
63    #[error("Invalid service descriptor: {message}")]
64    InvalidServiceDescriptor { message: String },
65
66    #[error("Dependency resolution failed for '{service_type}': {message}")]
67    DependencyResolutionFailed {
68        service_type: String,
69        message: String,
70    },
71
72    #[error("API error: {code} - {message}")]
73    Api {
74        code: String,
75        message: String,
76        hint: Option<String>,
77    },
78
79    #[error("Service initialization failed for '{service_type}': {source}")]
80    ServiceInitializationFailed {
81        service_type: String,
82        source: Box<dyn std::error::Error + Send + Sync>,
83    },
84}
85
86impl CoreError {
87    /// Create a new validation error
88    pub fn validation(message: impl Into<String>) -> Self {
89        Self::Validation {
90            message: message.into(),
91        }
92    }
93
94    /// Create a new configuration error
95    pub fn configuration(message: impl Into<String>) -> Self {
96        Self::Configuration {
97            message: message.into(),
98        }
99    }
100
101    /// Create a new service not found error
102    pub fn service_not_found(service_type: impl Into<String>) -> Self {
103        Self::ServiceNotFound {
104            service_type: service_type.into(),
105        }
106    }
107
108    /// Create a new system error
109    pub fn system_error(message: impl Into<String>) -> Self {
110        Self::SystemError {
111            message: message.into(),
112            source: None,
113        }
114    }
115
116    /// Create a new system error with source
117    pub fn system_error_with_source(
118        message: impl Into<String>,
119        source: Box<dyn std::error::Error + Send + Sync>,
120    ) -> Self {
121        Self::SystemError {
122            message: message.into(),
123            source: Some(source),
124        }
125    }
126
127    /// Create a new API error
128    pub fn api_error(code: impl Into<String>, message: impl Into<String>) -> Self {
129        Self::Api {
130            code: code.into(),
131            message: message.into(),
132            hint: None,
133        }
134    }
135
136    /// Add a hint to an API error
137    pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
138        if let Self::Api {
139            hint: ref mut h, ..
140        } = self
141        {
142            *h = Some(hint.into());
143        }
144        self
145    }
146
147    /// Check if the error is a validation error
148    pub fn is_validation(&self) -> bool {
149        matches!(self, Self::Validation { .. })
150    }
151
152    /// Check if the error is a configuration error
153    pub fn is_configuration(&self) -> bool {
154        matches!(self, Self::Configuration { .. })
155    }
156
157    /// Check if the error is a service error
158    pub fn is_service(&self) -> bool {
159        matches!(self, Self::ServiceNotFound { .. })
160    }
161}
162
163/// Error definition for the error catalog
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct ErrorDefinition {
166    pub code: String,
167    pub http: u16,
168    pub message: String,
169    pub hint: String,
170}
171
172/// API error response structure
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct ApiErrorResponse {
175    pub error: ApiError,
176}
177
178/// API error structure
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct ApiError {
181    pub code: String,
182    pub message: String,
183    pub hint: Option<String>,
184}
185
186impl ApiError {
187    /// Create a new API error
188    pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
189        Self {
190            code: code.into(),
191            message: message.into(),
192            hint: None,
193        }
194    }
195
196    /// Add a hint to the API error
197    pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
198        self.hint = Some(hint.into());
199        self
200    }
201}
202
203impl From<CoreError> for ApiError {
204    fn from(error: CoreError) -> Self {
205        match error {
206            CoreError::Api {
207                code,
208                message,
209                hint,
210            } => Self {
211                code,
212                message,
213                hint,
214            },
215            CoreError::Validation { message } => Self::new("VALIDATION_ERROR", message),
216            CoreError::Configuration { message } => Self::new("CONFIG_ERROR", message),
217            CoreError::ServiceNotFound { service_type } => Self::new(
218                "SERVICE_NOT_FOUND",
219                format!("Service not found: {}", service_type),
220            ),
221            _ => Self::new("INTERNAL_ERROR", error.to_string()),
222        }
223    }
224}
225
226impl From<ApiError> for ApiErrorResponse {
227    fn from(error: ApiError) -> Self {
228        Self { error }
229    }
230}
231
232/// Type alias for error catalog
233pub type ErrorCatalog = HashMap<String, ErrorDefinition>;
234
235/// Legacy alias for backward compatibility
236pub type ElifError = CoreError;