use std::error::Error;
use std::fmt;
#[derive(Debug, Clone)]
pub struct CallbackError {
message: String,
callback_type: Option<&'static str>,
}
impl CallbackError {
#[inline]
pub fn from_display<T: fmt::Display>(error: T) -> Self {
Self {
message: error.to_string(),
callback_type: None,
}
}
#[inline]
pub fn with_type<T: fmt::Display>(source_type: &'static str, error: T) -> Self {
Self {
message: error.to_string(),
callback_type: Some(source_type),
}
}
#[inline]
pub fn message(&self) -> &str {
&self.message
}
#[inline]
pub fn callback_type(&self) -> Option<&'static str> {
self.callback_type
}
#[inline]
pub fn is_typed(&self) -> bool {
self.callback_type.is_some()
}
}
impl fmt::Display for CallbackError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.callback_type {
Some(callback_type) => write!(f, "{}: {}", callback_type, self.message),
None => write!(f, "{}", self.message),
}
}
}
#[derive(Debug)]
pub enum ExecutorError<E> {
TaskFailed(E),
Panic(CallbackError),
PrepareFailed(CallbackError),
PrepareCommitFailed(CallbackError),
PrepareRollbackFailed {
original: CallbackError,
rollback: CallbackError,
},
}
impl<E> fmt::Display for ExecutorError<E>
where
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExecutorError::TaskFailed(e) => {
write!(f, "Task execution failed: {}", e)
}
ExecutorError::Panic(error) => {
write!(f, "Execution panicked: {}", error)
}
ExecutorError::PrepareFailed(msg) => {
write!(f, "Preparation action failed: {}", msg)
}
ExecutorError::PrepareCommitFailed(msg) => {
write!(f, "Prepare commit action failed: {}", msg)
}
ExecutorError::PrepareRollbackFailed { original, rollback } => {
write!(
f,
"Prepare rollback failed: original error = {}, rollback error = {}",
original, rollback
)
}
}
}
}
impl<E> ExecutorError<E> {
#[inline]
pub fn callback_type(&self) -> Option<&'static str> {
match self {
ExecutorError::TaskFailed(_) => None,
ExecutorError::Panic(error) => error.callback_type(),
ExecutorError::PrepareFailed(error) => error.callback_type(),
ExecutorError::PrepareCommitFailed(error) => error.callback_type(),
ExecutorError::PrepareRollbackFailed { original, rollback } => {
rollback.callback_type().or(original.callback_type())
}
}
}
}
impl<E> Error for ExecutorError<E>
where
E: Error + 'static,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
ExecutorError::TaskFailed(error) => Some(error),
ExecutorError::Panic(_)
| ExecutorError::PrepareFailed(_)
| ExecutorError::PrepareCommitFailed(_)
| ExecutorError::PrepareRollbackFailed { .. } => None,
}
}
}