use core::fmt::Display;
use core::marker::PhantomData;
use crate::tracer::{ErrorMessageTracer, ErrorTracer};
pub trait ErrorSource<Trace> {
type Source;
type Detail;
fn error_details(source: Self::Source) -> (Self::Detail, Option<Trace>);
}
pub type AsErrorDetail<Error, Trace> = <Error as ErrorSource<Trace>>::Detail;
pub type AsErrorSource<Error, Trace> = <Error as ErrorSource<Trace>>::Source;
pub struct NoSource;
pub struct DisplayError<E>(PhantomData<E>);
pub struct DisplayOnly<E>(PhantomData<E>);
pub struct TraceError<E>(PhantomData<E>);
pub struct TraceClone<E>(PhantomData<E>);
pub struct TraceOnly<Tracer>(PhantomData<Tracer>);
pub struct DetailOnly<Detail>(PhantomData<Detail>);
pub struct BoxDetail<Detail: ?Sized>(PhantomData<Detail>);
impl<Detail, Trace> ErrorSource<Trace> for DetailOnly<Detail> {
type Detail = Detail;
type Source = Detail;
fn error_details(source: Self::Source) -> (Self::Detail, Option<Trace>) {
(source, None)
}
}
impl<Trace> ErrorSource<Trace> for NoSource {
type Detail = ();
type Source = ();
fn error_details(_: Self::Source) -> (Self::Detail, Option<Trace>) {
((), None)
}
}
impl<Trace> ErrorSource<Trace> for TraceOnly<Trace> {
type Detail = ();
type Source = Trace;
fn error_details(source: Self::Source) -> (Self::Detail, Option<Trace>) {
((), Some(source))
}
}
impl<E, Tracer> ErrorSource<Tracer> for DisplayError<E>
where
E: Display,
Tracer: ErrorMessageTracer,
{
type Detail = E;
type Source = E;
fn error_details(source: Self::Source) -> (Self::Detail, Option<Tracer>) {
let trace = Tracer::new_message(&source);
(source, Some(trace))
}
}
impl<E, Tracer> ErrorSource<Tracer> for DisplayOnly<E>
where
E: Display,
Tracer: ErrorMessageTracer,
{
type Detail = ();
type Source = E;
fn error_details(source: Self::Source) -> (Self::Detail, Option<Tracer>) {
let trace = Tracer::new_message(&source);
((), Some(trace))
}
}
impl<E, Tracer> ErrorSource<Tracer> for TraceClone<E>
where
E: Clone,
Tracer: ErrorTracer<E>,
{
type Detail = E;
type Source = E;
fn error_details(source: Self::Source) -> (Self::Detail, Option<Tracer>) {
let detail = source.clone();
let trace = Tracer::new_trace(source);
(detail, Some(trace))
}
}
impl<E, Tracer> ErrorSource<Tracer> for TraceError<E>
where
Tracer: ErrorTracer<E>,
{
type Detail = ();
type Source = E;
fn error_details(source: Self::Source) -> (Self::Detail, Option<Tracer>) {
let trace = Tracer::new_trace(source);
((), Some(trace))
}
}