1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
use super::source::{DisplayError, ErrorSource, StdError}; use core::fmt::Display; /// An `ErrorMessageTracer` can be used to generically trace /// any error detail that implements [`Display`](std::fmt::Display). /// /// The error tracer may add backtrace information when the tracing /// methods are called. However since the error detail is required /// to only implement `Display`, any existing error trace may be /// lost even if the error detail implements `Error` and contains /// backtrace, unless the backtrace is serialized in `Display`. pub trait ErrorMessageTracer { /// Creates a new error trace, starting from a source error /// detail that implements [`Display`](std::fmt::Display). fn new_message<E: Display>(message: &E) -> Self; /// Adds new error detail to an existing trace. fn add_message<E: Display>(self, message: &E) -> Self; /// If the `std` feature is enabled, the error tracer /// also provides method to optionally converts itself /// to a `dyn` [`Error`](std::error::Error). #[cfg(feature = "std")] fn as_error(&self) -> Option<&(dyn std::error::Error + 'static)>; } /// An error tracer implements `ErrorTracer<E>` if it supports /// more sophisticated error tracing for an error type `E`. /// The contraint for `E` depends on the specific error tracer /// implementation. /// /// For example, [`EyreTracer`](crate::tracer_impl::eyre::EyreTracer) /// and [`AnyhowTracer`](crate::tracer_impl::anyhow::AnyhowTracer) requires /// an error type to satisfy `E: Error + Send + Sync + 'static`. /// /// The error tracer also requires ownership of the source error to be /// transferred to the error tracer. Because of this, it may not be possible /// to extract a source error type to be used as both error detail and /// error trace. We also should not expect `E` to implement `Clone`, as /// error types such as [`eyre::Report`] do not implement `Clone`. /// /// Note that because of restrictions on generic trait implementations outside /// of a Rust crate, it is not possible to generically implement `ErrorTracer<E>` /// for a custom error tracer outside of `flex-error`. If you want to define custom /// error tracers, you may need to make a copy of your own definition of /// `ErrorTracer` and also [`StdError`] in your own crate. pub trait ErrorTracer<E>: ErrorMessageTracer { /// Create a new error trace from `E`, also taking ownership of it. /// /// This calls the underlying methods such as [`eyre::Report::new`] /// and [`anyhow::Error::new`]. fn new_trace(err: E) -> Self; /// Add a new error trace from `E`. In the current underlying implementation, /// this is effectively still has the same behavior as /// [`ErrorMessageTracer::add_message`]. This is because [`eyre`] and /// [`anyhow`] do not support adding new set of backtraces to an existing /// trace. So effectively, currently the error tracers can track at most /// one backtrace coming from the original error source. fn add_trace(self, err: E) -> Self; } 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 StdError<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)) } }