fatal_error/
lib.rs

1//! Utility crate for differentiating fatal and non fatal errors
2use std::error::Error as StdError;
3
4/// An error that can never happend
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum NeverErr {}
7
8impl std::fmt::Display for NeverErr {
9    fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match *self {} }
10}
11
12impl std::error::Error for NeverErr {}
13
14/// Error type
15#[derive(Debug, PartialEq, Eq, Clone)]
16pub enum FatalError<E> {
17    /// Error
18    Error(E),
19    /// Fatal error
20    Fatal(E),
21}
22
23impl<E> FatalError<E> {
24    /// return true if this error non is fatal
25    pub fn is_error(&self) -> bool { matches!(self, FatalError::Error(_)) }
26
27    /// return true if this error is fatal
28    pub fn is_fatal(&self) -> bool { matches!(self, FatalError::Fatal(_)) }
29
30    /// transforms the error into it's inner type
31    pub fn into_inner(self) -> E {
32        match self {
33            FatalError::Error(x) => x,
34            FatalError::Fatal(x) => x,
35        }
36    }
37
38    /// applies f to the inner error preserving the [`FatalError::Error`] or [`FatalError::Fatal`] state
39    pub fn map<E2, F>(self, f: F) -> FatalError<E2>
40    where
41        F: FnOnce(E) -> E2,
42    {
43        match self {
44            FatalError::Error(x) => FatalError::Error(f(x)),
45            FatalError::Fatal(x) => FatalError::Fatal(f(x)),
46        }
47    }
48
49    /// Makes this error fatal
50    pub fn escalate(self) -> Self { FatalError::Fatal(self.into_inner()) }
51
52    /// Makes this error non fatal
53    pub fn deescalate(self) -> Self { FatalError::Error(self.into_inner()) }
54
55    /// Return `Ok(E)` if the error is non fatal else `Err(Self)` is returned
56    pub fn fatality(self) -> Result<E, Self> {
57        match self {
58            FatalError::Error(x) => Ok(x),
59            x @ FatalError::Fatal(_) => Err(x),
60        }
61    }
62
63    /// return `Err(E)` if the error is fatal otherwise `Ok(E)` is returned
64    pub fn recover(self) -> Result<E, E> {
65        match self {
66            FatalError::Error(x) => Ok(x),
67            FatalError::Fatal(x) => Err(x),
68        }
69    }
70
71    /// recover a non fatal error with the given closure
72    pub fn map_error<T, F>(self, f: F) -> Result<T, Self>
73    where
74        F: FnOnce(E) -> Result<T, Self>,
75    {
76        match self {
77            FatalError::Error(x) => f(x),
78            x @ FatalError::Fatal(_) => Err(x),
79        }
80    }
81
82    /// recover from a fatal error with the given closure
83    pub fn map_fatal<T, F>(self, f: F) -> Result<T, Self>
84    where
85        F: FnOnce(E) -> Result<T, Self>,
86    {
87        match self {
88            x @ FatalError::Error(_) => Err(x),
89            FatalError::Fatal(x) => f(x),
90        }
91    }
92
93    /// recover from either an error or a fatal error with the given closure
94    pub fn then<T, F>(self, f: F) -> Result<T, Self>
95    where
96        F: FnOnce(E) -> Result<T, Self>,
97    {
98        f(self.into_inner())
99    }
100}
101
102impl<E: std::fmt::Display> std::fmt::Display for FatalError<E> {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        match self {
105            FatalError::Error(x) => write!(f, "Error: {x}"),
106            FatalError::Fatal(x) => write!(f, "Fatal Error: {x}"),
107        }
108    }
109}
110
111impl<E: StdError + 'static> StdError for FatalError<E> {
112    fn source(&self) -> Option<&(dyn StdError + 'static)> {
113        match self {
114            FatalError::Error(x) | FatalError::Fatal(x) => x.source(),
115        }
116    }
117}