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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
use core::marker::PhantomData; /// A type implementing `ErrorSource<Trace>` is a proxy type that provides the /// capability of extracting from an error source of type `Self::Source`, /// returning error detail of type `Self::Detail`, and an optional error /// tracer of type `Tracer`. /// /// The proxy type `Self` is not used anywhere. We separate out `Self` /// and `Self::Source` so that there can be different generic implementations /// of error sources, such as for all `E: Display` or for all `E: Error`. /// /// There are currently 4 types of error sources: /// - [`NoSource`] - Indicating the lack of any error source /// - [`DisplayError`] - An error source that implements [`Display`](std::fmt::Display). /// - [`DetailOnly`] - An error source that do not contain any error trace /// - [`StdError`] - An error source that implements [`Error`](std::error::Error) with no detail. /// - [`ErrorReport`](crate::report::ErrorReport) - An error type defined by `flex-error` that contains /// both error details and error traces. pub trait ErrorSource<Trace> { /// The type of the error source. type Source; /// The type of the error detail that can be extracted from the error source type Detail; /// Extracts the error details out from the error source, together with /// an optional error trace. fn error_details(source: Self::Source) -> (Self::Detail, Option<Trace>); } /// Type alias to `<Error as ErrorSource<Trace>>::Detail` pub type AsErrorDetail<Error, Trace> = <Error as ErrorSource<Trace>>::Detail; /// Type alias to `<Error as ErrorSource<Trace>>::Source` pub type AsErrorSource<Error, Trace> = <Error as ErrorSource<Trace>>::Source; /// An [`ErrorSource`] that can be used to represent to lack of any error source. /// Both its `Source` and `Detail` types are `()`. This can be used for primitive errors /// that are not caused by any error source. /// /// In practice, it is also possible to omit specifying any error source inside /// [`define_error!`](crate::define_error), which has similar effect as using /// `NoSource` but with the `source` field omitted entirely. pub struct NoSource; /// An [`ErrorSource`] that implements [`Display`](std::fmt::Display) and /// can be traced by error tracers implementing [`ErrorMessageTracer`](crate::tracer::ErrorMessageTracer). /// /// Both its `Source` and `Detail` types are `E`. When extraced, it also provides /// an error trace that is traced from its string representation. pub struct DisplayError<E>(PhantomData<E>); /// An [`ErrorSource`] that should implement [`Error`](std::error::Error) and /// other constraints such as `Send`, `Sync`, `'static`, so that it can be traced /// by error tracing libraries such as [`eyre`] and [`anyhow`]. Because these libraries /// take ownership of the source error object, the error cannot be extracted as detail /// at the same time. pub struct StdError<E>(PhantomData<E>); /// An [`ErrorSource`] that contains only the error trace with no detail. /// This can for example be used for upstream functions that return tracers like /// [`eyre::Report`] directly. /// /// Note that the `Tracer` type must be the same as the tracer type defined in /// [`ErrorReport`](crate::ErrorReport), and most likely it should also be the same as /// [`DefaultTracer`](crate::DefaultTracer). /// If you plan to use `flex-error` with different feature flags, you should /// classify the source as [`StdError`] instead. pub struct TraceOnly<Tracer>(PhantomData<Tracer>); /// An [`ErrorSource`] that only provides error details but do not provide any trace. /// This can typically comes from primitive error types that do not implement /// [`Error`](std::error::Error). The `Detail` type is the error and the returned /// trace is `None`. /// /// It is also possible to omit specifying the error as an error source, and instead /// place it as a field in the error variant. However specifying it as a `DetailOnly` /// source may give stronger hint to the reader that the particular error variant /// is caused by other underlying errors. pub struct DetailOnly<Detail>(PhantomData<Detail>); impl<Detail, Trace> ErrorSource<Trace> for DetailOnly<Detail> { type Detail = Detail; type Source = Detail; fn error_details(source: Self::Source) -> (Self::Detail, Option<Trace>) { (source, None) } } impl<Trace> ErrorSource<Trace> for NoSource { type Detail = (); type Source = (); fn error_details(_: Self::Source) -> (Self::Detail, Option<Trace>) { ((), None) } } impl <Trace> ErrorSource<Trace> for TraceOnly<Trace> { type Detail = (); type Source = Trace; fn error_details(source: Self::Source) -> (Self::Detail, Option<Trace>) { ((), Some(source)) } }