1use std::fmt;
2use std::path::PathBuf;
3use std::io;
4
5#[cfg(feature = "serde")]
6use serde::Serialize;
7
8pub type Result<T> = std::result::Result<T, crate::error::AppError>;
10
11pub trait ForgeError: std::error::Error + Send + Sync {
13 fn kind(&self) -> &'static str;
14 fn caption(&self) -> &'static str;
15 fn is_retryable(&self) -> bool {
16 false
17 }
18 fn is_fatal(&self) -> bool {
19 true
20 }
21 fn status_code(&self) -> u16 {
22 500
23 }
24 fn exit_code(&self) -> i32 {
25 1
26 }
27}
28
29#[derive(Debug)]
31#[cfg_attr(feature = "serde", derive(Serialize))]
32pub enum AppError {
33 Config { message: String },
34 Filesystem { path: Option<PathBuf>, source: io::Error },
35 Other { message: String },
36}
37
38impl std::fmt::Display for AppError {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 Self::Config { message } => write!(f, "⚙️ Config: {}", message),
42 Self::Filesystem { path, source } => write!(f, "💾 IO: {:?} ({})", path, source),
43 Self::Other { message } => write!(f, "🚨 Error: {}", message),
44 }
45 }
46}
47
48impl std::error::Error for AppError {
49 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
50 match self {
51 AppError::Filesystem { source, .. } => Some(source),
52 _ => None,
53 }
54 }
55}
56
57impl From<io::Error> for AppError {
58 fn from(e: io::Error) -> Self {
59 AppError::Filesystem { path: None, source: e }
60 }
61}