1use std::fmt;
7use thiserror::Error;
8
9pub type NeuroDivergentResult<T> = Result<T, NeuroDivergentError>;
11
12#[derive(Error, Debug)]
14pub enum NeuroDivergentError {
15 #[error("Model configuration error: {message}")]
17 ConfigError {
18 message: String,
20 source: Option<Box<dyn std::error::Error + Send + Sync>>,
22 },
23
24 #[error("Data validation error: {message}")]
26 DataError {
27 message: String,
29 field: Option<String>,
31 source: Option<Box<dyn std::error::Error + Send + Sync>>,
33 },
34
35 #[error("Training error: {message}")]
37 TrainingError {
38 message: String,
40 epoch: Option<usize>,
42 source: Option<Box<dyn std::error::Error + Send + Sync>>,
44 },
45
46 #[error("Prediction error: {message}")]
48 PredictionError {
49 message: String,
51 model_name: Option<String>,
53 source: Option<Box<dyn std::error::Error + Send + Sync>>,
55 },
56
57 #[error("Network integration error: {0}")]
59 NetworkError(#[from] NetworkIntegrationError),
60
61 #[error("I/O error: {0}")]
63 IoError(#[from] std::io::Error),
64
65 #[error("Serialization error: {message}")]
67 SerializationError {
68 message: String,
70 format: Option<String>,
72 source: Option<Box<dyn std::error::Error + Send + Sync>>,
74 },
75
76 #[error("Memory error: {message}")]
78 MemoryError {
79 message: String,
81 memory_usage: Option<usize>,
83 source: Option<Box<dyn std::error::Error + Send + Sync>>,
85 },
86
87 #[error("Compatibility error: {message}")]
89 CompatibilityError {
90 message: String,
92 components: Option<Vec<String>>,
94 source: Option<Box<dyn std::error::Error + Send + Sync>>,
96 },
97
98 #[error("Mathematical error: {message}")]
100 MathError {
101 message: String,
103 operation: Option<String>,
105 source: Option<Box<dyn std::error::Error + Send + Sync>>,
107 },
108
109 #[error("Parallel processing error: {message}")]
111 ParallelError {
112 message: String,
114 thread_info: Option<String>,
116 source: Option<Box<dyn std::error::Error + Send + Sync>>,
118 },
119
120 #[error("Time series error: {message}")]
122 TimeSeriesError {
123 message: String,
125 series_id: Option<String>,
127 timestamp: Option<chrono::DateTime<chrono::Utc>>,
129 source: Option<Box<dyn std::error::Error + Send + Sync>>,
131 },
132}
133
134#[derive(Error, Debug)]
136pub enum NetworkIntegrationError {
137 #[error("Network architecture mismatch: expected {expected}, found {found}")]
139 ArchitectureMismatch {
140 expected: String,
142 found: String,
144 },
145
146 #[error("Training algorithm error: {message}")]
148 TrainingAlgorithmError {
149 message: String,
151 algorithm: Option<String>,
153 },
154
155 #[error("Network I/O error: {message}")]
157 NetworkIoError {
158 message: String,
160 path: Option<String>,
162 },
163
164 #[error("Network validation error: {message}")]
166 ValidationError {
167 message: String,
169 layer: Option<usize>,
171 },
172
173 #[error("Activation function error: {message}")]
175 ActivationError {
176 message: String,
178 function: Option<String>,
180 },
181}
182
183pub struct ErrorBuilder {
185 error_type: ErrorType,
186 message: String,
187 source: Option<Box<dyn std::error::Error + Send + Sync>>,
188 context: std::collections::HashMap<String, String>,
189}
190
191enum ErrorType {
193 Config,
194 Data,
195 Training,
196 Prediction,
197 Memory,
198 Compatibility,
199 Math,
200 Parallel,
201 TimeSeries,
202 Serialization,
203}
204
205impl ErrorBuilder {
206 pub fn config<S: Into<String>>(message: S) -> Self {
208 Self {
209 error_type: ErrorType::Config,
210 message: message.into(),
211 source: None,
212 context: std::collections::HashMap::new(),
213 }
214 }
215
216 pub fn data<S: Into<String>>(message: S) -> Self {
218 Self {
219 error_type: ErrorType::Data,
220 message: message.into(),
221 source: None,
222 context: std::collections::HashMap::new(),
223 }
224 }
225
226 pub fn training<S: Into<String>>(message: S) -> Self {
228 Self {
229 error_type: ErrorType::Training,
230 message: message.into(),
231 source: None,
232 context: std::collections::HashMap::new(),
233 }
234 }
235
236 pub fn prediction<S: Into<String>>(message: S) -> Self {
238 Self {
239 error_type: ErrorType::Prediction,
240 message: message.into(),
241 source: None,
242 context: std::collections::HashMap::new(),
243 }
244 }
245
246 pub fn memory<S: Into<String>>(message: S) -> Self {
248 Self {
249 error_type: ErrorType::Memory,
250 message: message.into(),
251 source: None,
252 context: std::collections::HashMap::new(),
253 }
254 }
255
256 pub fn time_series<S: Into<String>>(message: S) -> Self {
258 Self {
259 error_type: ErrorType::TimeSeries,
260 message: message.into(),
261 source: None,
262 context: std::collections::HashMap::new(),
263 }
264 }
265
266 pub fn source<E: std::error::Error + Send + Sync + 'static>(mut self, source: E) -> Self {
268 self.source = Some(Box::new(source));
269 self
270 }
271
272 pub fn context<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
274 self.context.insert(key.into(), value.into());
275 self
276 }
277
278 pub fn build(self) -> NeuroDivergentError {
280 match self.error_type {
281 ErrorType::Config => NeuroDivergentError::ConfigError {
282 message: self.message,
283 source: self.source,
284 },
285 ErrorType::Data => NeuroDivergentError::DataError {
286 message: self.message,
287 field: self.context.get("field").cloned(),
288 source: self.source,
289 },
290 ErrorType::Training => NeuroDivergentError::TrainingError {
291 message: self.message,
292 epoch: self.context.get("epoch").and_then(|s| s.parse().ok()),
293 source: self.source,
294 },
295 ErrorType::Prediction => NeuroDivergentError::PredictionError {
296 message: self.message,
297 model_name: self.context.get("model_name").cloned(),
298 source: self.source,
299 },
300 ErrorType::Memory => NeuroDivergentError::MemoryError {
301 message: self.message,
302 memory_usage: self.context.get("memory_usage").and_then(|s| s.parse().ok()),
303 source: self.source,
304 },
305 ErrorType::Compatibility => NeuroDivergentError::CompatibilityError {
306 message: self.message,
307 components: self.context.get("components")
308 .map(|s| s.split(',').map(|s| s.trim().to_string()).collect()),
309 source: self.source,
310 },
311 ErrorType::Math => NeuroDivergentError::MathError {
312 message: self.message,
313 operation: self.context.get("operation").cloned(),
314 source: self.source,
315 },
316 ErrorType::Parallel => NeuroDivergentError::ParallelError {
317 message: self.message,
318 thread_info: self.context.get("thread_info").cloned(),
319 source: self.source,
320 },
321 ErrorType::TimeSeries => NeuroDivergentError::TimeSeriesError {
322 message: self.message,
323 series_id: self.context.get("series_id").cloned(),
324 timestamp: self.context.get("timestamp")
325 .and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
326 .map(|dt| dt.with_timezone(&chrono::Utc)),
327 source: self.source,
328 },
329 ErrorType::Serialization => NeuroDivergentError::SerializationError {
330 message: self.message,
331 format: self.context.get("format").cloned(),
332 source: self.source,
333 },
334 }
335 }
336}
337
338#[macro_export]
340macro_rules! config_error {
341 ($msg:expr) => {
342 $crate::error::ErrorBuilder::config($msg).build()
343 };
344 ($msg:expr, $($key:expr => $value:expr),+) => {
345 {
346 let mut builder = $crate::error::ErrorBuilder::config($msg);
347 $(
348 builder = builder.context($key, $value);
349 )+
350 builder.build()
351 }
352 };
353}
354
355#[macro_export]
357macro_rules! data_error {
358 ($msg:expr) => {
359 $crate::error::ErrorBuilder::data($msg).build()
360 };
361 ($msg:expr, field = $field:expr) => {
362 $crate::error::ErrorBuilder::data($msg).context("field", $field).build()
363 };
364 ($msg:expr, $($key:expr => $value:expr),+) => {
365 {
366 let mut builder = $crate::error::ErrorBuilder::data($msg);
367 $(
368 builder = builder.context($key, $value);
369 )+
370 builder.build()
371 }
372 };
373}
374
375#[macro_export]
377macro_rules! training_error {
378 ($msg:expr) => {
379 $crate::error::ErrorBuilder::training($msg).build()
380 };
381 ($msg:expr, epoch = $epoch:expr) => {
382 $crate::error::ErrorBuilder::training($msg).context("epoch", $epoch.to_string()).build()
383 };
384 ($msg:expr, $($key:expr => $value:expr),+) => {
385 {
386 let mut builder = $crate::error::ErrorBuilder::training($msg);
387 $(
388 builder = builder.context($key, $value);
389 )+
390 builder.build()
391 }
392 };
393}
394
395#[cfg(test)]
396mod tests {
397 use super::*;
398
399 #[test]
400 fn test_error_builder_config() {
401 let error = ErrorBuilder::config("Test configuration error")
402 .context("parameter", "learning_rate")
403 .build();
404
405 match error {
406 NeuroDivergentError::ConfigError { message, .. } => {
407 assert_eq!(message, "Test configuration error");
408 }
409 _ => panic!("Expected ConfigError"),
410 }
411 }
412
413 #[test]
414 fn test_error_builder_data() {
415 let error = ErrorBuilder::data("Test data error")
416 .context("field", "target_column")
417 .build();
418
419 match error {
420 NeuroDivergentError::DataError { message, field, .. } => {
421 assert_eq!(message, "Test data error");
422 assert_eq!(field, Some("target_column".to_string()));
423 }
424 _ => panic!("Expected DataError"),
425 }
426 }
427
428 #[test]
429 fn test_error_macros() {
430 let error = config_error!("Configuration problem");
431 assert!(matches!(error, NeuroDivergentError::ConfigError { .. }));
432
433 let error = data_error!("Data problem", field = "timestamp");
434 match error {
435 NeuroDivergentError::DataError { field, .. } => {
436 assert_eq!(field, Some("timestamp".to_string()));
437 }
438 _ => panic!("Expected DataError"),
439 }
440 }
441
442 #[test]
443 fn test_network_integration_error() {
444 let error = NetworkIntegrationError::ArchitectureMismatch {
445 expected: "3-5-1".to_string(),
446 found: "3-4-1".to_string(),
447 };
448
449 let error_string = error.to_string();
450 assert!(error_string.contains("3-5-1"));
451 assert!(error_string.contains("3-4-1"));
452 }
453
454 #[test]
455 fn test_error_chaining() {
456 let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "File not found");
457 let error = ErrorBuilder::data("Could not read data file")
458 .source(io_error)
459 .build();
460
461 match error {
462 NeuroDivergentError::DataError { source, .. } => {
463 assert!(source.is_some());
464 }
465 _ => panic!("Expected DataError"),
466 }
467 }
468}