use crate::Actor;
use std::fmt::Debug;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FailurePhase {
OnStart,
OnIdle,
OnStop,
OnIdleThenOnStop,
}
impl std::fmt::Display for FailurePhase {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
#[derive(Debug)]
pub enum ActorFailure<T: Actor> {
OnStart {
error: T::Error,
},
OnIdle {
actor: T,
error: T::Error,
},
OnStop {
actor: T,
error: T::Error,
},
OnIdleThenOnStop {
actor: T,
error: T::Error,
stop_error: T::Error,
},
}
impl<T: Actor> ActorFailure<T> {
pub fn phase(&self) -> FailurePhase {
match self {
ActorFailure::OnStart { .. } => FailurePhase::OnStart,
ActorFailure::OnIdle { .. } => FailurePhase::OnIdle,
ActorFailure::OnStop { .. } => FailurePhase::OnStop,
ActorFailure::OnIdleThenOnStop { .. } => FailurePhase::OnIdleThenOnStop,
}
}
pub fn error(&self) -> &T::Error {
match self {
ActorFailure::OnStart { error }
| ActorFailure::OnIdle { error, .. }
| ActorFailure::OnStop { error, .. }
| ActorFailure::OnIdleThenOnStop { error, .. } => error,
}
}
pub fn into_error(self) -> T::Error {
match self {
ActorFailure::OnStart { error }
| ActorFailure::OnIdle { error, .. }
| ActorFailure::OnStop { error, .. }
| ActorFailure::OnIdleThenOnStop { error, .. } => error,
}
}
pub fn actor(&self) -> Option<&T> {
match self {
ActorFailure::OnStart { .. } => None,
ActorFailure::OnIdle { actor, .. }
| ActorFailure::OnStop { actor, .. }
| ActorFailure::OnIdleThenOnStop { actor, .. } => Some(actor),
}
}
pub fn into_actor(self) -> Option<T> {
match self {
ActorFailure::OnStart { .. } => None,
ActorFailure::OnIdle { actor, .. }
| ActorFailure::OnStop { actor, .. }
| ActorFailure::OnIdleThenOnStop { actor, .. } => Some(actor),
}
}
pub fn stop_error(&self) -> Option<&T::Error> {
match self {
ActorFailure::OnIdleThenOnStop { stop_error, .. } => Some(stop_error),
_ => None,
}
}
pub fn into_stop_error(self) -> Option<T::Error> {
match self {
ActorFailure::OnIdleThenOnStop { stop_error, .. } => Some(stop_error),
_ => None,
}
}
}
#[derive(Debug)]
pub enum ActorResult<T: Actor> {
Completed {
actor: T,
killed: bool,
},
Failed {
failure: ActorFailure<T>,
killed: bool,
},
}
impl<T: Actor> From<ActorResult<T>> for (Option<T>, Option<T::Error>) {
fn from(result: ActorResult<T>) -> Self {
match result {
ActorResult::Completed { actor, .. } => (Some(actor), None),
ActorResult::Failed { failure, .. } => match failure {
ActorFailure::OnStart { error } => (None, Some(error)),
ActorFailure::OnIdle { actor, error }
| ActorFailure::OnStop { actor, error }
| ActorFailure::OnIdleThenOnStop { actor, error, .. } => (Some(actor), Some(error)),
},
}
}
}
impl<T: Actor> ActorResult<T> {
pub fn is_completed(&self) -> bool {
matches!(self, ActorResult::Completed { .. })
}
pub fn was_killed(&self) -> bool {
matches!(
self,
ActorResult::Completed { killed: true, .. } | ActorResult::Failed { killed: true, .. }
)
}
pub fn stopped_normally(&self) -> bool {
matches!(self, ActorResult::Completed { killed: false, .. })
}
pub fn phase(&self) -> Option<FailurePhase> {
match self {
ActorResult::Completed { .. } => None,
ActorResult::Failed { failure, .. } => Some(failure.phase()),
}
}
pub fn is_startup_failed(&self) -> bool {
matches!(
self,
ActorResult::Failed {
failure: ActorFailure::OnStart { .. },
..
}
)
}
pub fn is_runtime_failed(&self) -> bool {
matches!(
self,
ActorResult::Failed {
failure: ActorFailure::OnIdle { .. } | ActorFailure::OnIdleThenOnStop { .. },
..
}
)
}
pub fn is_cleanup_failed(&self) -> bool {
matches!(
self,
ActorResult::Failed {
failure: ActorFailure::OnIdleThenOnStop { .. },
..
}
)
}
pub fn is_stop_failed(&self) -> bool {
matches!(
self,
ActorResult::Failed {
failure: ActorFailure::OnStop { .. } | ActorFailure::OnIdleThenOnStop { .. },
..
}
)
}
pub fn actor(&self) -> Option<&T> {
match self {
ActorResult::Completed { actor, .. } => Some(actor),
ActorResult::Failed { failure, .. } => failure.actor(),
}
}
pub fn into_actor(self) -> Option<T> {
match self {
ActorResult::Completed { actor, .. } => Some(actor),
ActorResult::Failed { failure, .. } => failure.into_actor(),
}
}
pub fn error(&self) -> Option<&T::Error> {
match self {
ActorResult::Completed { .. } => None,
ActorResult::Failed { failure, .. } => Some(failure.error()),
}
}
pub fn into_error(self) -> Option<T::Error> {
match self {
ActorResult::Completed { .. } => None,
ActorResult::Failed { failure, .. } => Some(failure.into_error()),
}
}
pub fn secondary_error(&self) -> Option<&T::Error> {
match self {
ActorResult::Failed { failure, .. } => failure.stop_error(),
ActorResult::Completed { .. } => None,
}
}
pub fn into_secondary_error(self) -> Option<T::Error> {
match self {
ActorResult::Failed { failure, .. } => failure.into_stop_error(),
ActorResult::Completed { .. } => None,
}
}
pub fn is_failed(&self) -> bool {
!self.is_completed()
}
pub fn has_actor(&self) -> bool {
self.actor().is_some()
}
pub fn into_result(self) -> std::result::Result<T, T::Error> {
match self {
ActorResult::Completed { actor, .. } => Ok(actor),
ActorResult::Failed { failure, .. } => Err(failure.into_error()),
}
}
}