use std::borrow::Cow;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::panic::Location;
use crate::pointer_utils::ToBox;
#[derive(Debug)]
pub struct ServiceError {
trace: ErrorTrace,
kind: ServiceErrorKind,
source: Option<Box<dyn Error + Send>>,
}
impl Display for ServiceError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.kind {
ServiceErrorKind::InternalError { code } => {
write!(f, "internal error [error_code = `{code}`]")?;
}
ServiceErrorKind::DependencyError { dependency_name, code, } => {
write!(f, "dependency error [dependency_name = `{dependency_name}`] [error_code = `{code}`]")?;
}
};
Ok(())
}
}
impl Error for ServiceError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.source {
None => { None }
Some(err) => { Some(&**err) }
}
}
}
impl ServiceError {
pub fn internal_error(
code: Cow<'static, str>,
source: Option<Box<dyn Error + Send>>,
trace: ErrorTrace,
) -> ServiceError {
ServiceError {
trace,
source,
kind: ServiceErrorKind::InternalError { code },
}
}
pub fn dependency_error(
dependency_name: Cow<'static, str>,
code: Cow<'static, str>,
source: Option<Box<dyn Error + Send>>,
trace: ErrorTrace,
) -> ServiceError {
ServiceError {
trace,
source,
kind: ServiceErrorKind::DependencyError {
code,
dependency_name,
},
}
}
pub fn set_error<T>(&mut self, error: T)
where T: Error + Send + 'static
{
self.source = Some(error.boxed())
}
pub fn with_error<T>(mut self, error: T) -> ServiceError
where T: Error + Send + 'static
{
self.set_error(error);
self
}
pub fn trace(&self) -> &ErrorTrace {
&self.trace
}
}
#[derive(Debug)]
enum ServiceErrorKind {
InternalError {
code: Cow<'static, str>,
},
DependencyError {
code: Cow<'static, str>,
dependency_name: Cow<'static, str>,
},
}
#[derive(Debug)]
pub enum ErrorTrace {
Location(&'static Location<'static>),
}