use serde::{Deserialize, Serialize};
use thiserror::Error;
pub type TypedResult<T> = Result<T, TypedError>;
pub type LeveledResult<T> = Result<T, LeveledError>;
#[derive(Error, Debug, Serialize, Deserialize, Clone, Copy)]
pub enum SystemError {
#[error("Configuration error")]
Config,
#[error("Module config error")]
ModuleConfig,
#[error("Partition config error")]
PartitionConfig,
#[error("Error during Partition initialization")]
PartitionInit,
#[error("Segmentation error occured")]
Segmentation,
#[error("Time duration was exceeded by periodic process")]
TimeDurationExceeded,
#[error("Application error raised in partition")]
ApplicationError,
#[error("Unrecoverable errors")]
Panic,
#[error("Floating point error occurred")]
FloatingPoint,
#[error("cgroup related error")]
CGroup,
}
#[derive(Debug, Clone, Copy)]
pub enum ErrorLevel {
Partition,
ModuleInit,
ModuleRun,
}
#[derive(Error, Debug)]
#[error("{err:?}: {source:?}")]
pub struct TypedError {
err: SystemError,
source: anyhow::Error,
}
impl TypedError {
pub fn new(err: SystemError, source: anyhow::Error) -> Self {
Self { err, source }
}
pub fn err(&self) -> SystemError {
self.err
}
pub fn source(&self) -> &anyhow::Error {
&self.source
}
}
#[derive(Error, Debug)]
#[error("{err:?}: {level:?}, {source:?}")]
pub struct LeveledError {
err: SystemError,
level: ErrorLevel,
source: anyhow::Error,
}
impl LeveledError {
pub fn new(err: SystemError, level: ErrorLevel, source: anyhow::Error) -> Self {
Self { err, level, source }
}
pub fn err(&self) -> SystemError {
self.err
}
pub fn level(&self) -> ErrorLevel {
self.level
}
pub fn source(&self) -> &anyhow::Error {
&self.source
}
}
impl From<LeveledError> for TypedError {
fn from(le: LeveledError) -> Self {
Self {
err: le.err,
source: le.source,
}
}
}
pub trait ResultExt<T> {
fn typ(self, err: SystemError) -> TypedResult<T>;
fn lev_typ(self, err: SystemError, level: ErrorLevel) -> LeveledResult<T>;
}
pub trait TypedResultExt<T> {
fn lev(self, level: ErrorLevel) -> LeveledResult<T>;
}
impl<T> TypedResultExt<T> for TypedResult<T> {
fn lev(self, level: ErrorLevel) -> LeveledResult<T> {
self.map_err(|e| LeveledError {
err: e.err,
level,
source: e.source,
})
}
}
impl<T, E: Into<anyhow::Error>> ResultExt<T> for Result<T, E> {
fn typ(self, err: SystemError) -> TypedResult<T> {
self.map_err(|e| TypedError {
err,
source: e.into(),
})
}
fn lev_typ(self, err: SystemError, level: ErrorLevel) -> LeveledResult<T> {
self.map_err(|e| LeveledError {
err,
level,
source: e.into(),
})
}
}