use std::{any, fmt, ops};
use crate::{
common::error::{AnyError, PsuedoError},
item::{self, IdT},
};
#[derive(Debug)]
pub struct Error {
inner: AnyError,
context: Option<Context>,
}
impl ops::Deref for Error {
type Target = dyn std::error::Error;
fn deref(&self) -> &Self::Target {
self.as_error()
}
}
impl Error {
fn new<E: std::error::Error + Send + Sync + 'static>(error: E) -> Self {
Self {
inner: AnyError::new(error),
context: None,
}
}
pub(crate) fn with_context<T>(mut self, id: IdT<T>) -> Self {
self.context = Some(Context {
id: id.untyped(),
type_name: any::type_name::<T>(),
});
self
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { inner, context } = self;
write!(f, "Item ")?;
if let Some(context) = context {
write!(f, " {context}")?;
}
write!(f, "not found: {inner}")?;
Ok(())
}
}
impl<E: std::error::Error + Send + Sync + 'static> From<E> for Error {
fn from(value: E) -> Self {
Self::new(value)
}
}
impl PsuedoError for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
std::error::Error::source(self.inner.as_error())
}
}
#[derive(Debug)]
pub(crate) struct Context {
id: item::Id,
type_name: &'static str,
}
impl fmt::Display for Context {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { id, type_name } = self;
write!(f, "{id} ({type_name})")?;
Ok(())
}
}