a653rs_linux_core/
error.rs

1//! Error handling for this crate
2use serde::{Deserialize, Serialize};
3use thiserror::Error;
4
5/// A Result containing a SystemError with its accompanying source
6pub type TypedResult<T> = Result<T, TypedError>;
7/// A Result containing a SystemError with its accompanying error and time
8/// window
9// TODO: Consider merging these two types by making level an Option.
10pub type LeveledResult<T> = Result<T, LeveledError>;
11
12/// A low-level error issued by the operating system
13///
14/// This implementation is custom. Do not confuse it with the traditional unix
15/// errnos.
16// TODO: Why can't we just use traditional unix errnos? The anyhow messages should be
17// concrete enough.
18#[derive(Error, Debug, Serialize, Deserialize, Clone, Copy)]
19pub enum SystemError {
20    #[error("Configuration error")]
21    Config,
22    #[error("Module config error")]
23    ModuleConfig,
24    #[error("Partition config error")]
25    PartitionConfig,
26    #[error("Error during Partition initialization")]
27    PartitionInit,
28    #[error("Segmentation error occured")]
29    Segmentation,
30    #[error("Time duration was exceeded by periodic process")]
31    TimeDurationExceeded,
32    #[error("Application error raised in partition")]
33    ApplicationError,
34    #[error("Unrecoverable errors")]
35    Panic,
36    #[error("Floating point error occurred")]
37    FloatingPoint,
38    #[error("cgroup related error")]
39    CGroup,
40}
41
42/// The time window in which the error has occurred
43#[derive(Debug, Clone, Copy)]
44pub enum ErrorLevel {
45    /// Synchronous to Partition Time Window
46    Partition,
47    /// During Module Init Phase
48    ModuleInit,
49    /// Asynchronous to Partition Time Window
50    ModuleRun,
51}
52
53/// Combination of a SystemError with an anyhow error
54#[derive(Error, Debug)]
55#[error("{err:?}: {source:?}")]
56pub struct TypedError {
57    err: SystemError,
58    source: anyhow::Error,
59}
60
61impl TypedError {
62    /// Creates a new TypedError
63    pub fn new(err: SystemError, source: anyhow::Error) -> Self {
64        Self { err, source }
65    }
66    /// Returns the SystemError of this TypedError
67    pub fn err(&self) -> SystemError {
68        self.err
69    }
70    /// Returns the anyhow error of this TypedError
71    pub fn source(&self) -> &anyhow::Error {
72        &self.source
73    }
74}
75
76/// Combination of a SystemError with an anyhow error and its time window
77// TODO: Consider naming "level" "source" instead, as it indicates in which
78// time window the error has occurred?
79#[derive(Error, Debug)]
80#[error("{err:?}: {level:?}, {source:?}")]
81pub struct LeveledError {
82    err: SystemError,
83    level: ErrorLevel,
84    source: anyhow::Error,
85}
86
87impl LeveledError {
88    /// Creates a new LeveledError
89    pub fn new(err: SystemError, level: ErrorLevel, source: anyhow::Error) -> Self {
90        Self { err, level, source }
91    }
92    /// Returns the SystemError of this TypedError
93    pub fn err(&self) -> SystemError {
94        self.err
95    }
96    /// Returns the ErrorLevel of this TypedError
97    pub fn level(&self) -> ErrorLevel {
98        self.level
99    }
100    /// Returns the anyhow error of this TypedError
101    pub fn source(&self) -> &anyhow::Error {
102        &self.source
103    }
104}
105impl From<LeveledError> for TypedError {
106    fn from(le: LeveledError) -> Self {
107        // Basically just cut off the level field
108        Self {
109            err: le.err,
110            source: le.source,
111        }
112    }
113}
114
115/// Converts a Result into one of our own Result types
116pub trait ResultExt<T> {
117    /// Converts a Result to a TypedResult
118    fn typ(self, err: SystemError) -> TypedResult<T>;
119    /// Converts a Result to a LeveledResult
120    fn lev_typ(self, err: SystemError, level: ErrorLevel) -> LeveledResult<T>;
121}
122
123/// Converts a TypedResult to one of our own Result types
124pub trait TypedResultExt<T> {
125    /// Creates a LeveledResult from a TypedResult
126    fn lev(self, level: ErrorLevel) -> LeveledResult<T>;
127}
128
129impl<T> TypedResultExt<T> for TypedResult<T> {
130    fn lev(self, level: ErrorLevel) -> LeveledResult<T> {
131        // This basically just creates a LeveledError with all fields tken even from
132        // the TypedResult, except the level being added.
133        self.map_err(|e| LeveledError {
134            err: e.err,
135            level,
136            source: e.source,
137        })
138    }
139}
140
141impl<T, E: Into<anyhow::Error>> ResultExt<T> for Result<T, E> {
142    fn typ(self, err: SystemError) -> TypedResult<T> {
143        self.map_err(|e| TypedError {
144            err,
145            source: e.into(),
146        })
147    }
148
149    fn lev_typ(self, err: SystemError, level: ErrorLevel) -> LeveledResult<T> {
150        self.map_err(|e| LeveledError {
151            err,
152            level,
153            source: e.into(),
154        })
155    }
156}