diff --git a/src/handlers/debug.rs b/src/handlers/debug.rs index 50450a4..db2bca2 100644 --- a/src/handlers/debug.rs +++ b/src/handlers/debug.rs @@ -1,6 +1,6 @@ use std::fmt; -use crate::{protocol::Diagnostic, ReportHandler}; +use crate::{protocol::Diagnostic, AsDiagnostic, ReportHandler}; /** [`ReportHandler`] that renders plain text and avoids extraneous graphics. @@ -31,8 +31,9 @@ impl DebugReportHandler { pub fn render_report( &self, f: &mut fmt::Formatter<'_>, - diagnostic: &(dyn Diagnostic), + diagnostic: impl AsDiagnostic, ) -> fmt::Result { + let diagnostic = diagnostic.as_dyn(); let mut diag = f.debug_struct("Diagnostic"); diag.field("message", &format!("{}", diagnostic)); if let Some(code) = diagnostic.code() { diff --git a/src/handlers/graphical.rs b/src/handlers/graphical.rs index 8c4a9a5..b0a8654 100644 --- a/src/handlers/graphical.rs +++ b/src/handlers/graphical.rs @@ -7,7 +7,7 @@ use crate::diagnostic_chain::{DiagnosticChain, ErrorKind}; use crate::handlers::theme::*; use crate::highlighters::{Highlighter, MietteHighlighter}; use crate::protocol::{Diagnostic, Severity}; -use crate::{LabeledSpan, ReportHandler, SourceCode, SourceSpan, SpanContents}; +use crate::{AsDiagnostic, LabeledSpan, ReportHandler, SourceCode, SourceSpan, SpanContents}; /** A [`ReportHandler`] that displays a given [`Report`](crate::Report) in a @@ -216,8 +216,9 @@ impl GraphicalReportHandler { pub fn render_report( &self, f: &mut impl fmt::Write, - diagnostic: &(dyn Diagnostic), + diagnostic: impl AsDiagnostic, ) -> fmt::Result { + let diagnostic = diagnostic.as_dyn(); self.render_header(f, diagnostic)?; self.render_causes(f, diagnostic)?; let src = diagnostic.source_code(); diff --git a/src/handlers/json.rs b/src/handlers/json.rs index 0b4a405..9ad6fc4 100644 --- a/src/handlers/json.rs +++ b/src/handlers/json.rs @@ -1,7 +1,8 @@ use std::fmt::{self, Write}; use crate::{ - diagnostic_chain::DiagnosticChain, protocol::Diagnostic, ReportHandler, Severity, SourceCode, + diagnostic_chain::DiagnosticChain, protocol::Diagnostic, AsDiagnostic, ReportHandler, Severity, + SourceCode, }; /** @@ -60,8 +61,9 @@ impl JSONReportHandler { pub fn render_report( &self, f: &mut impl fmt::Write, - diagnostic: &(dyn Diagnostic), + diagnostic: impl AsDiagnostic, ) -> fmt::Result { + let diagnostic = diagnostic.as_dyn(); self._render_report(f, diagnostic, None) } diff --git a/src/handlers/narratable.rs b/src/handlers/narratable.rs index f8d36ae..bed54f2 100644 --- a/src/handlers/narratable.rs +++ b/src/handlers/narratable.rs @@ -4,7 +4,9 @@ use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; use crate::diagnostic_chain::DiagnosticChain; use crate::protocol::{Diagnostic, Severity}; -use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents}; +use crate::{ + AsDiagnostic, LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents, +}; /** [`ReportHandler`] that renders plain text and avoids extraneous graphics. @@ -69,8 +71,9 @@ impl NarratableReportHandler { pub fn render_report( &self, f: &mut impl fmt::Write, - diagnostic: &(dyn Diagnostic), + diagnostic: impl AsDiagnostic, ) -> fmt::Result { + let diagnostic = diagnostic.as_dyn(); self.render_header(f, diagnostic)?; if self.with_cause_chain { self.render_causes(f, diagnostic)?; diff --git a/src/protocol.rs b/src/protocol.rs index 7f09d4d..5b91c8d 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -12,7 +12,7 @@ use std::{ #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::MietteError; +use crate::{MietteError, Report}; /// Adds rich metadata to your Error that can be used by /// [`Report`](crate::Report) to print really nice and human-friendly error @@ -69,6 +69,48 @@ pub trait Diagnostic: std::error::Error { } } +macro_rules! blanket_ref_impls { + ($($ref_type:ty),+ $(,)?) => { + $( + impl Diagnostic for $ref_type { + fn code<'a>(&'a self) -> Option> { + (**self).code() + } + + fn severity(&self) -> Option { + (**self).severity() + } + + fn help<'a>(&'a self) -> Option> { + (**self).help() + } + + fn url<'a>(&'a self) -> Option> { + (**self).url() + } + + fn source_code(&self) -> Option<&dyn SourceCode> { + (**self).source_code() + } + + fn labels(&self) -> Option + '_>> { + (**self).labels() + } + + fn related<'a>(&'a self) -> Option + 'a>> { + (**self).related() + } + + fn diagnostic_source(&self) -> Option<&dyn Diagnostic> { + (**self).diagnostic_source() + } + } + )+ + }; +} + +blanket_ref_impls!(&T, Box); + macro_rules! box_error_impls { ($($box_type:ty),*) => { $( @@ -189,6 +231,44 @@ impl From> for Box &dyn Diagnostic; +} + +impl AsDiagnostic for &dyn Diagnostic { + fn as_dyn(&self) -> &dyn Diagnostic { + *self + } +} + +impl AsDiagnostic for Report { + fn as_dyn(&self) -> &dyn Diagnostic { + self.as_ref() + } +} + +macro_rules! blanket_ref_impls { + ($($ref_type:ty),+ $(,)?) => { + $( + impl AsDiagnostic for $ref_type { + fn as_dyn(&self) -> &dyn Diagnostic { + (**self).as_dyn() + } + } + )+ + }; +} + +blanket_ref_impls!(&Report, &mut Report, Box); + +impl AsDiagnostic for T { + fn as_dyn(&self) -> &dyn Diagnostic { + self + } +} + /** [`Diagnostic`] severity. Intended to be used by [`ReportHandler`](crate::ReportHandler)s to change the way different diff --git a/tests/graphical.rs b/tests/graphical.rs index 3176812..271b870 100644 --- a/tests/graphical.rs +++ b/tests/graphical.rs @@ -13,24 +13,24 @@ fn fmt_report(diag: Report) -> String { GraphicalReportHandler::new_themed(GraphicalTheme::unicode()) .with_width(80) .with_footer("this is a footer".into()) - .render_report(&mut out, diag.as_ref()) + .render_report(&mut out, &diag) .unwrap(); } else if std::env::var("NARRATED").is_ok() { NarratableReportHandler::new() - .render_report(&mut out, diag.as_ref()) + .render_report(&mut out, diag) .unwrap(); } else if let Ok(w) = std::env::var("REPLACE_TABS") { GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor()) .without_syntax_highlighting() .with_width(80) .tab_width(w.parse().expect("Invalid tab width.")) - .render_report(&mut out, diag.as_ref()) + .render_report(&mut out, &diag) .unwrap(); } else { GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor()) .without_syntax_highlighting() .with_width(80) - .render_report(&mut out, diag.as_ref()) + .render_report(&mut out, &diag) .unwrap(); }; out @@ -46,7 +46,7 @@ fn fmt_report_with_settings( GraphicalTheme::unicode_nocolor(), )); - handler.render_report(&mut out, diag.as_ref()).unwrap(); + handler.render_report(&mut out, diag).unwrap(); println!("Error:\n```\n{}\n```", out); diff --git a/tests/narrated.rs b/tests/narrated.rs index 52acd13..b3cde4e 100644 --- a/tests/narrated.rs +++ b/tests/narrated.rs @@ -12,11 +12,11 @@ fn fmt_report(diag: Report) -> String { if cfg!(feature = "fancy-no-backtrace") && std::env::var("STYLE").is_ok() { #[cfg(feature = "fancy-no-backtrace")] GraphicalReportHandler::new_themed(GraphicalTheme::unicode()) - .render_report(&mut out, diag.as_ref()) + .render_report(&mut out, diag) .unwrap(); } else { NarratableReportHandler::new() - .render_report(&mut out, diag.as_ref()) + .render_report(&mut out, diag) .unwrap(); }; out diff --git a/tests/test_blanket.rs b/tests/test_blanket.rs new file mode 100644 index 0000000..58271ca --- /dev/null +++ b/tests/test_blanket.rs @@ -0,0 +1,13 @@ +use miette::{Diagnostic, MietteDiagnostic}; + +fn assert_diagnostic() {} + +#[test] +fn test_ref() { + assert_diagnostic::<&MietteDiagnostic>() +} + +#[test] +fn test_box() { + assert_diagnostic::>() +} diff --git a/tests/test_json.rs b/tests/test_json.rs index 664318a..091fa0a 100644 --- a/tests/test_json.rs +++ b/tests/test_json.rs @@ -8,7 +8,7 @@ mod json_report_handler { fn fmt_report(diag: Report) -> String { let mut out = String::new(); JSONReportHandler::new() - .render_report(&mut out, diag.as_ref()) + .render_report(&mut out, diag) .unwrap(); out }