use std::{error::Error, fmt, io, string::FromUtf8Error, sync::Arc};
#[derive(Default, Debug, Clone)]
pub struct AppError {
pub message: String,
pub source: Option<Arc<dyn std::error::Error + Send + Sync>>,
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(source) = &self.source {
write!(f, "{} (caused by: {})", self.message, source)
} else {
write!(f, "{}", self.message)
}
}
}
impl AppError {
#[must_use]
pub fn new(message: String) -> Self {
Self {
message,
source: None,
}
}
pub fn new_with_source<S: Into<String>>(
message: S,
source: Arc<dyn std::error::Error + Send + Sync>,
) -> Self {
Self {
message: message.into(),
source: Some(source),
}
}
}
impl From<String> for AppError {
fn from(message: String) -> Self {
Self::new(message)
}
}
impl From<&str> for AppError {
fn from(message: &str) -> Self {
Self::new(message.to_string())
}
}
impl From<io::Error> for AppError {
fn from(error: io::Error) -> Self {
Self {
message: error.to_string(),
source: Some(Arc::new(error)),
}
}
}
impl From<FromUtf8Error> for AppError {
fn from(error: FromUtf8Error) -> Self {
Self {
message: error.to_string(),
source: Some(Arc::new(error)),
}
}
}
impl From<std::num::ParseFloatError> for AppError {
fn from(error: std::num::ParseFloatError) -> Self {
Self {
message: error.to_string(),
source: Some(Arc::new(error)),
}
}
}
impl Error for AppError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.source.as_ref().map(|arc| {
let err: &(dyn Error + 'static) = &**arc;
err
})
}
}
impl<S, B> From<(S, B)> for AppError
where
S: Into<String>,
B: std::error::Error + Send + Sync + 'static,
{
fn from(value: (S, B)) -> Self {
AppError::new_with_source(value.0.into(), Arc::new(value.1))
}
}
#[derive(Debug, Default)]
pub struct ErrorManager {
pub(crate) errors: Vec<AppError>,
pub(crate) is_open: bool,
pub(crate) was_open: bool,
}
impl ErrorManager {
#[must_use]
pub fn new() -> Self {
Self {
..Default::default()
}
}
pub fn add_error<E: Into<AppError>>(&mut self, error: E) {
self.errors.push(error.into());
}
#[must_use]
pub(crate) fn title() -> &'static str {
"Error window"
}
#[must_use]
pub fn is_some_error(&self) -> bool {
!self.errors.is_empty()
}
pub fn clear(&mut self) {
self.errors.clear();
}
}