bladvak/
errors.rs

1//! Error handling
2
3use std::{error::Error, fmt, io, string::FromUtf8Error, sync::Arc};
4
5/// Type for error
6#[derive(Default, Debug, Clone)]
7enum ErrorType {
8    /// Normal error
9    #[default]
10    Normal,
11    /// Fake error
12    Fake,
13}
14
15/// AppError object
16#[derive(Default, Debug)]
17pub struct AppError {
18    /// Error message
19    pub message: String,
20    /// Error source
21    pub source: Option<Arc<dyn std::error::Error + Send + Sync>>,
22    /// Error type
23    error_type: ErrorType,
24}
25
26impl Clone for AppError {
27    fn clone(&self) -> Self {
28        Self {
29            message: self.message.clone(),
30            source: self.source.clone(),
31            error_type: self.error_type.clone(),
32        }
33    }
34}
35
36impl fmt::Display for AppError {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        // Print the message and optionally the source
39        if let Some(source) = &self.source {
40            write!(f, "{} (caused by: {})", self.message, source)
41        } else {
42            write!(f, "{}", self.message)
43        }
44    }
45}
46
47impl AppError {
48    /// Create new AppError
49    pub fn new(message: String) -> Self {
50        Self {
51            message,
52            source: None,
53            error_type: ErrorType::Normal,
54        }
55    }
56
57    /// Create new Normal
58    pub fn new_with_source(source: Arc<dyn std::error::Error + Send + Sync>) -> Self {
59        Self {
60            message: source.to_string(),
61            source: Some(source),
62            error_type: ErrorType::Normal,
63        }
64    }
65
66    /// Create fake error
67    pub fn new_fake(message: String) -> Self {
68        Self {
69            message,
70            source: None,
71            error_type: ErrorType::Fake,
72        }
73    }
74
75    /// Check if error is fake
76    pub fn is_fake(&self) -> bool {
77        matches!(self.error_type, ErrorType::Fake)
78    }
79}
80
81impl From<String> for AppError {
82    fn from(message: String) -> Self {
83        Self::new(message)
84    }
85}
86
87impl From<&str> for AppError {
88    fn from(message: &str) -> Self {
89        Self::new(message.to_string())
90    }
91}
92
93impl From<io::Error> for AppError {
94    fn from(error: io::Error) -> Self {
95        Self {
96            message: error.to_string(),
97            source: Some(Arc::new(error)),
98            error_type: ErrorType::Normal,
99        }
100    }
101}
102
103impl From<FromUtf8Error> for AppError {
104    fn from(error: FromUtf8Error) -> Self {
105        Self {
106            message: error.to_string(),
107            source: Some(Arc::new(error)),
108            error_type: ErrorType::Normal,
109        }
110    }
111}
112
113impl Error for AppError {
114    fn source(&self) -> Option<&(dyn Error + 'static)> {
115        // Return a reference to the inner error, if present
116        // Arc doesn’t allow direct coercion, so we must use `as_ref()` and a cast
117        self.source.as_ref().map(|arc| {
118            let err: &(dyn Error + 'static) = &**arc;
119            err
120        })
121    }
122}
123
124/// Error handler
125#[derive(Debug, Default)]
126pub struct ErrorManager {
127    /// List of errors
128    pub errors: Vec<AppError>,
129
130    /// Check if it is open
131    pub is_open: bool,
132
133    /// Check if it was open
134    pub was_open: bool,
135}
136
137impl ErrorManager {
138    /// New Error manager
139    pub fn new() -> Self {
140        Self {
141            ..Default::default()
142        }
143    }
144
145    /// Add an error
146    pub fn add_error(&mut self, error: AppError) {
147        if error.is_fake() {
148            return;
149        }
150        self.errors.push(error);
151    }
152
153    /// Handle an error
154    pub fn handle_error<T>(&mut self, error: Result<T, impl Into<AppError>>) -> Option<T> {
155        match error {
156            Ok(value) => Some(value),
157            Err(e) => {
158                self.add_error(e.into());
159                None
160            }
161        }
162    }
163
164    /// Errors Title
165    pub fn title(&self) -> &'static str {
166        "Error window"
167    }
168}