fatality/
lib.rs

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