use std::backtrace::Backtrace;
use std::error::Error as StdError;
use std::fmt;
use ohno::{ErrorExt, OhnoCore};
use crate::Enrichable;
#[derive(ohno::Error, Clone)]
struct Inner {
inner: OhnoCore,
}
#[derive(Clone)]
pub struct AppError {
inner: Inner,
}
impl AppError {
pub fn new<E>(error: E) -> Self
where
E: Into<Box<dyn StdError + Send + Sync + 'static>>,
{
Self {
inner: Inner {
inner: OhnoCore::from(error),
},
}
}
#[must_use]
pub fn source(&self) -> Option<&(dyn StdError + 'static)> {
StdError::source(&self.inner)
}
#[must_use]
pub fn root_cause(&self) -> &(dyn StdError + 'static) {
let mut source: &(dyn StdError + 'static) = &self.inner;
while let Some(next) = StdError::source(source) {
source = next;
}
source
}
#[must_use]
pub fn find_source<T: StdError + 'static>(&self) -> Option<&T> {
let mut source = self.source();
while let Some(err) = source {
if let Some(target) = err.downcast_ref::<T>() {
return Some(target);
}
source = StdError::source(err);
}
None
}
pub fn backtrace(&self) -> &Backtrace {
self.inner.backtrace()
}
#[must_use]
pub fn message(&self) -> String {
self.inner.message()
}
#[must_use]
pub fn into_std_error(self) -> Box<dyn StdError + Send + Sync + 'static> {
Box::new(self.inner)
}
#[must_use]
pub fn downcast_ref<T: StdError + 'static>(&self) -> Option<&T> {
self.source().and_then(|source| source.downcast_ref::<T>())
}
}
impl fmt::Debug for AppError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.inner, f)
}
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.inner, f)
}
}
impl<E> From<E> for AppError
where
E: StdError + Send + Sync + 'static,
{
fn from(error: E) -> Self {
Self::new(error)
}
}
impl AsRef<dyn StdError + Send + Sync + 'static> for AppError {
fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
&self.inner
}
}
impl Enrichable for AppError {
fn add_enrichment(&mut self, entry: crate::EnrichmentEntry) {
self.inner.add_enrichment(entry);
}
}
impl From<AppError> for Box<dyn StdError + Send + Sync + 'static> {
fn from(err: AppError) -> Self {
err.into_std_error()
}
}