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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
use core::fmt::Display; use core::marker::PhantomData; use crate::tracer::{ErrorMessageTracer, ErrorTracer}; /// 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). /// - [`DisplayOnly`] - An error source that implements [`Display`](std::fmt::Display) and do not provide additional detail. /// - [`DetailOnly`] - An error source that do not contain any error trace /// - [`TraceError`] - 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>); pub struct DisplayOnly<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 TraceError<E>(PhantomData<E>); pub struct TraceClone<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 [`TraceError`] 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>); pub struct BoxDetail<Detail: ?Sized>(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)) } } 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 DisplayOnly<E> where E: Display, Tracer: ErrorMessageTracer, { type Detail = (); type Source = E; fn error_details(source: Self::Source) -> (Self::Detail, Option<Tracer>) { let trace = Tracer::new_message(&source); ((), Some(trace)) } } impl<E, Tracer> ErrorSource<Tracer> for TraceClone<E> where E: Clone, Tracer: ErrorTracer<E>, { type Detail = E; type Source = E; fn error_details(source: Self::Source) -> (Self::Detail, Option<Tracer>) { let detail = source.clone(); let trace = Tracer::new_trace(source); (detail, Some(trace)) } } impl<E, Tracer> ErrorSource<Tracer> for TraceError<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)) } }