Skip to main content

error_fatality/
lib.rs

1#![deny(clippy::dbg_macro)]
2
3//! Declarative annotations for `fatal` or `jfyi` error variants.
4//!
5//! Expand `#[derive(Split)]` annotations on error type definitions into two
6//! additional error type definitions that can be converted back to the
7//! original, or the original can be split into one of the two generated error
8//! types.
9//! Determination of fatality can also be forwarded to an inner error that
10//! implements the `Fatality` trait.
11//!
12//! Stands on the shoulders of `thiserror`.
13
14pub use error_fatality_proc_macro::{Fatality, Split};
15
16/// Determine the fatality of an error.
17pub trait Fatality: std::error::Error + std::fmt::Debug {
18    /// Returns `true` if the error variant is _fatal_
19    /// or `false` if it is more of a informational error.
20    fn is_fatal(&self) -> bool;
21}
22
23/// Allows to split an error into two types - a fatal
24/// and a informational enum error type, that can be further consumed.
25pub trait Split: std::error::Error + std::fmt::Debug {
26    type Fatal: std::error::Error + Send + Sync + 'static;
27    type Jfyi: std::error::Error + Send + Sync + 'static;
28
29    /// Split the error into it's fatal and non-fatal variants.
30    ///
31    /// `Ok(jfyi)` contains a enum representing all non-fatal variants, `Err(fatal)`
32    /// contains all fatal variants.
33    ///
34    /// Attention: If the type is splitable, it must _not_ use any `forward`ed
35    /// finality evaluations,
36    /// or it must be splitable up the point where no more `forward`
37    /// annotations were used.
38    fn split(self) -> std::result::Result<Self::Jfyi, Self::Fatal>;
39}
40
41/// Converts a flat, yet `splitable` error into a nested `Result<Result<_,Jfyi>, Fatal>`
42/// error type.
43pub trait Nested<T, E: Split>
44where
45    Self: Sized,
46{
47    /// Convert into a nested error rather than a flat one, commonly for direct handling.
48    fn into_nested(
49        self,
50    ) -> std::result::Result<
51        std::result::Result<T, <E as Split>::Jfyi>,
52        <E as Split>::Fatal,
53    >;
54}
55
56impl<T, E: Split> Nested<T, E> for std::result::Result<T, E> {
57    fn into_nested(
58        self,
59    ) -> std::result::Result<
60        std::result::Result<T, <E as Split>::Jfyi>,
61        <E as Split>::Fatal,
62    > {
63        match self {
64            Ok(t) => Ok(Ok(t)),
65            Err(e) => match e.split() {
66                Ok(jfyi) => Ok(Err(jfyi)),
67                Err(fatal) => Err(fatal),
68            },
69        }
70    }
71}
72
73#[cfg(test)]
74mod test;