use core::fmt::Display;
use super::{
Attachment, ContextMap, ErrorCode, MissingSeverity, Report, ReportMetadata, ReportOptions,
ReportSourceErrorIter, Severity, SeverityState, StackTrace,
};
pub trait Diagnostic {
type Value;
type Error;
fn to_report(self) -> Result<Self::Value, Report<Self::Error>>;
fn diag<E2, State2>(
self,
f: impl FnOnce(Report<Self::Error>) -> Report<E2, State2>,
) -> Result<Self::Value, Report<E2, State2>>
where
Self: Sized,
State2: SeverityState,
{
self.to_report().map_err(f)
}
fn to_report_note(
self,
message: impl Display + Send + Sync + 'static,
) -> Result<Self::Value, Report<Self::Error>>
where
Self: Sized,
{
self.to_report().and_then_report(
|report: Report<Self::Error, MissingSeverity>| -> Report<Self::Error, MissingSeverity> {
Report::<Self::Error, MissingSeverity>::attach_note(report, message)
},
)
}
}
impl<T, E> Diagnostic for Result<T, E> {
type Value = T;
type Error = E;
fn to_report(self) -> Result<Self::Value, Report<Self::Error>> {
self.map_err(Report::new)
}
}
macro_rules! define_ext_method {
($(#[$attr:meta])* fn $name:ident($($arg:ident : $ty:ty),*) -> Self) => {
$(#[$attr])*
fn $name(self, $($arg: $ty),*) -> Self;
};
($(#[$attr:meta])* fn $name:ident <$($gen:ident),*> ($($arg:ident : $ty:ty $(,)? )* ) -> Self where $($bound:tt)*) => {
$(#[$attr])*
fn $name <$($gen),*> (self, $($arg: $ty),*) -> Self where $($bound)*;
};
($(#[$attr:meta])* fn $name:ident($($arg:ident : $ty:ty $(,)? )* ) -> $ret:ty [STATE_CHANGE]) => {
$(#[$attr])*
fn $name(self, $($arg: $ty),*) -> $ret;
};
}
macro_rules! impl_ext_method {
($(#[$attr:meta])* fn $name:ident($($arg:ident : $ty:ty),*) -> Self) => {
fn $name(self, $($arg: $ty),*) -> Self {
self.map_err(|r| r.$name($($arg),*))
}
};
($(#[$attr:meta])* fn $name:ident <$($gen:ident),*> ($($arg:ident : $ty:ty $(,)? )* ) -> Self where $($bound:tt)*) => {
fn $name <$($gen),*> (self, $($arg: $ty),*) -> Self where $($bound)* {
self.map_err(|r| r.$name($($arg),*))
}
};
($(#[$attr:meta])* fn $name:ident($($arg:ident : $ty:ty $(,)? )* ) -> $ret:ty [STATE_CHANGE]) => {
fn $name(self, $($arg: $ty),*) -> $ret {
self.map_err(|r| r.$name($($arg),*))
}
};
}
pub trait ResultReportExt<T, E, State = MissingSeverity>
where
State: SeverityState,
{
fn and_then_report<NewE, NewState>(
self,
f: impl FnOnce(Report<E, State>) -> Report<NewE, NewState>,
) -> Result<T, Report<NewE, NewState>>
where
NewState: SeverityState;
fn map_report_err<NewE>(self, f: impl FnOnce(E) -> NewE) -> Result<T, Report<NewE, State>>
where
E: core::error::Error + Send + Sync + 'static,
NewE: core::error::Error + Send + Sync + 'static;
fn into_report_inner(self) -> Result<T, E>;
for_each_report_builder_method!(define_ext_method);
}
impl<T, E, State> ResultReportExt<T, E, State> for Result<T, Report<E, State>>
where
State: SeverityState,
{
fn and_then_report<NewE, NewState>(
self,
f: impl FnOnce(Report<E, State>) -> Report<NewE, NewState>,
) -> Result<T, Report<NewE, NewState>>
where
NewState: SeverityState,
{
self.map_err(f)
}
fn map_report_err<NewE>(self, f: impl FnOnce(E) -> NewE) -> Result<T, Report<NewE, State>>
where
E: core::error::Error + Send + Sync + 'static,
NewE: core::error::Error + Send + Sync + 'static,
{
self.map_err(|r| r.map_err(f))
}
fn into_report_inner(self) -> Result<T, E> {
self.map_err(|r| r.into_inner())
}
for_each_report_builder_method!(impl_ext_method);
}
pub trait InspectReportExt<T, E, State = MissingSeverity>
where
State: SeverityState,
{
fn report_ref(&self) -> Option<&Report<E, State>>;
fn report_inner(&self) -> Option<&E>;
fn report_attachments(&self) -> Option<&[Attachment]>;
fn report_context(&self) -> Option<&ContextMap>;
fn report_system(&self) -> Option<&ContextMap>;
fn report_metadata(&self) -> Option<&ReportMetadata<State>>;
fn report_error_code(&self) -> Option<&ErrorCode>;
fn report_severity(&self) -> Option<Severity>;
fn report_category(&self) -> Option<&str>;
fn report_retryable(&self) -> Option<bool>;
fn report_stack_trace(&self) -> Option<&StackTrace>;
fn report_options(&self) -> Option<&ReportOptions>;
fn report_display_causes(
&self,
) -> Option<&[alloc::sync::Arc<dyn core::fmt::Display + Send + Sync>]>;
fn report_iter_origin_sources(&self) -> Option<ReportSourceErrorIter<'_>>
where
E: core::error::Error;
fn report_iter_diag_sources(&self) -> Option<ReportSourceErrorIter<'_>>
where
E: core::error::Error;
}
impl<T, E, State> InspectReportExt<T, E, State> for Result<T, Report<E, State>>
where
State: SeverityState,
{
fn report_ref(&self) -> Option<&Report<E, State>> {
self.as_ref().err()
}
fn report_inner(&self) -> Option<&E> {
self.report_ref().map(Report::<E, State>::inner)
}
fn report_attachments(&self) -> Option<&[Attachment]> {
self.report_ref().map(Report::<E, State>::attachments)
}
fn report_context(&self) -> Option<&ContextMap> {
self.report_ref().map(Report::<E, State>::context)
}
fn report_system(&self) -> Option<&ContextMap> {
self.report_ref().map(Report::<E, State>::system)
}
fn report_metadata(&self) -> Option<&ReportMetadata<State>> {
self.report_ref().map(Report::<E, State>::metadata)
}
fn report_error_code(&self) -> Option<&ErrorCode> {
self.report_ref().and_then(Report::<E, State>::error_code)
}
fn report_severity(&self) -> Option<Severity> {
self.report_ref().and_then(Report::<E, State>::severity)
}
fn report_category(&self) -> Option<&str> {
self.report_ref().and_then(Report::<E, State>::category)
}
fn report_retryable(&self) -> Option<bool> {
self.report_ref().and_then(Report::<E, State>::retryable)
}
fn report_stack_trace(&self) -> Option<&StackTrace> {
self.report_ref().and_then(Report::<E, State>::stack_trace)
}
fn report_options(&self) -> Option<&ReportOptions> {
self.report_ref().map(Report::<E, State>::options)
}
fn report_display_causes(
&self,
) -> Option<&[alloc::sync::Arc<dyn core::fmt::Display + Send + Sync>]> {
self.report_ref().map(Report::<E, State>::display_causes)
}
fn report_iter_origin_sources(&self) -> Option<ReportSourceErrorIter<'_>>
where
E: core::error::Error,
{
self.report_ref()
.map(Report::<E, State>::iter_origin_sources)
}
fn report_iter_diag_sources(&self) -> Option<ReportSourceErrorIter<'_>>
where
E: core::error::Error,
{
self.report_ref().map(Report::<E, State>::iter_diag_sources)
}
}