diff --git a/src/lib.rs b/src/lib.rs index eee1b9a6..2ba32d79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(missing_docs, missing_debug_implementations, nonstandard_style)] +// #![deny(missing_docs, missing_debug_implementations, nonstandard_style)] #![warn(unreachable_pub, rust_2018_idioms)] //! You run miette? You run her code like the software? Oh. Oh! Error code for //! coder! Error code for One Thousand Lines! @@ -801,3 +801,6 @@ mod named_source; mod panic; mod protocol; mod source_impls; +mod typed_report; + +pub use typed_report::*; diff --git a/src/typed_report.rs b/src/typed_report.rs new file mode 100644 index 00000000..572c1668 --- /dev/null +++ b/src/typed_report.rs @@ -0,0 +1,68 @@ +use std::any::{Any, TypeId}; +use std::backtrace::Backtrace; +use std::error::Error; +use std::ops::Deref; + +pub type TypedResult = Result>; + +pub struct TypedReport { + error: T, + backtrace: Backtrace, +} + +impl TypedReport { + pub fn unwrap(self) -> T { + self.error + } + + pub fn inner(&self) -> &T { + self.error.as_ref() + } + + pub fn backtrace(&self) -> &Backtrace { + self.backtrace.as_ref() + } +} + +impl Deref for TypedReport { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.error.as_ref().unwrap() + } +} + +impl From for TypedReport +where + T: Any + Error + 'static, + U: Any + Error + 'static, + V: Any + Error + 'static + From, +{ + fn from(value: U) -> Self { + let val = if TypeId::of::() == TypeId::of::>() { + value.unwrap().into() + } else { + value + }; + TypedReport { + error: val, + backtrace: Backtrace::capture(), + } + } +} + +impl From> for TypedReport +where + T: Any + Error + 'static, + U: Any + Error + 'static + From, +{ + fn from(value: TypedReport) -> Self { + if TypeId::of::() == TypeId::of::() { + return value + } + TypedReport { + error: value.error.take().map(|x| x.into()), + backtrace: value.backtrace.take(), + } + } +} diff --git a/tests/typed_report.rs b/tests/typed_report.rs new file mode 100644 index 00000000..2d84f6be --- /dev/null +++ b/tests/typed_report.rs @@ -0,0 +1,44 @@ +use miette::{Diagnostic, TypedReport}; +use thiserror::Error; + +#[test] +fn into_typed() { + #[derive(Debug, Diagnostic, Error)] + #[error("oops!")] + #[diagnostic(code(error::on::base))] + struct MyBad { + #[source_code] + src: String, + #[label("this bit here")] + highlight: (usize, usize), + } + + let src = "source\n text\n here".to_string(); + let err = MyBad { + src, + highlight: (9, 4), + }; + let typed_err: TypedReport<_> = err.into(); + assert_eq!(typed_err.code().unwrap().to_string(), "error::on::base"); +} + +#[test] +fn backtrace_retention() { + #[derive(Debug, Error)] + #[error("oops!")] + struct MyBad; + + #[derive(Debug, Error)] + #[error("also fail: {0}")] + struct AlsoBad(#[from] MyBad); + + let typed_err: TypedReport<_> = MyBad.into(); + let backtrace1 = typed_err.backtrace().to_string(); + + let other: TypedReport = typed_err.into(); + + let backtrace2 = other.backtrace().to_string(); + + assert_eq!(backtrace1, backtrace2); +} +