mirror of https://github.com/zkat/miette.git
TypedReport: a dream that can never be :(
Basically, the idea was to have something like 'Report' that would be strongly typed, except I ran into the exact same reason that anyhow doesn't do this: the blanket `From` impl :( So this is, in essence, impossible to do ergonomically, but I'm keeping this around for future reference.
This commit is contained in:
parent
01564e070f
commit
3315cd3010
|
|
@ -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)]
|
#![warn(unreachable_pub, rust_2018_idioms)]
|
||||||
#![allow(unexpected_cfgs)]
|
#![allow(unexpected_cfgs)]
|
||||||
//! You run miette? You run her code like the software? Oh. Oh! Error code for
|
//! You run miette? You run her code like the software? Oh. Oh! Error code for
|
||||||
|
|
@ -804,3 +804,6 @@ mod named_source;
|
||||||
mod panic;
|
mod panic;
|
||||||
mod protocol;
|
mod protocol;
|
||||||
mod source_impls;
|
mod source_impls;
|
||||||
|
mod typed_report;
|
||||||
|
|
||||||
|
pub use typed_report::*;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
use std::any::{Any, TypeId};
|
||||||
|
use std::backtrace::Backtrace;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
pub type TypedResult<T, E> = Result<T, TypedReport<E>>;
|
||||||
|
|
||||||
|
pub struct TypedReport<T: Error + 'static> {
|
||||||
|
error: T,
|
||||||
|
backtrace: Backtrace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Error + 'static> TypedReport<T> {
|
||||||
|
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<T: Error + 'static> Deref for TypedReport<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.error.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U, V> From<U> for TypedReport<T>
|
||||||
|
where
|
||||||
|
T: Any + Error + 'static,
|
||||||
|
U: Any + Error + 'static,
|
||||||
|
V: Any + Error + 'static + From<T>,
|
||||||
|
{
|
||||||
|
fn from(value: U) -> Self {
|
||||||
|
let val = if TypeId::of::<U>() == TypeId::of::<TypedReport<V>>() {
|
||||||
|
value.unwrap().into()
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
};
|
||||||
|
TypedReport {
|
||||||
|
error: val,
|
||||||
|
backtrace: Backtrace::capture(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> From<TypedReport<T>> for TypedReport<U>
|
||||||
|
where
|
||||||
|
T: Any + Error + 'static,
|
||||||
|
U: Any + Error + 'static + From<T>,
|
||||||
|
{
|
||||||
|
fn from(value: TypedReport<T>) -> Self {
|
||||||
|
if TypeId::of::<T>() == TypeId::of::<U>() {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
TypedReport {
|
||||||
|
error: value.error.take().map(|x| x.into()),
|
||||||
|
backtrace: value.backtrace.take(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<AlsoBad> = typed_err.into();
|
||||||
|
|
||||||
|
let backtrace2 = other.backtrace().to_string();
|
||||||
|
|
||||||
|
assert_eq!(backtrace1, backtrace2);
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue