use std::{fmt, time::Duration};
use thiserror::Error;
pub type ActorResult<T> = std::result::Result<T, ActorError>;
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum ActorRequest {
Aborted,
Exit,
Restart(Option<Duration>),
}
#[derive(Error, Debug)]
#[error("Source: {source}, request: {request:?}")]
pub struct ActorError {
pub source: anyhow::Error,
pub request: Option<ActorRequest>,
}
impl Default for ActorError {
fn default() -> Self {
Self {
source: anyhow::anyhow!("An unknown error occurred!"),
request: None,
}
}
}
pub trait ActorResultExt {
type Error;
fn err_request(self, request: ActorRequest) -> ActorResult<Self::Error>
where
Self: Sized;
}
impl<T> ActorResultExt for anyhow::Result<T> {
type Error = T;
fn err_request(self, request: ActorRequest) -> ActorResult<T>
where
Self: Sized,
{
match self {
Err(source) => Err(ActorError {
source,
request: request.into(),
}),
Ok(t) => Ok(t),
}
}
}
impl From<anyhow::Error> for ActorError {
fn from(source: anyhow::Error) -> Self {
Self { source, request: None }
}
}
impl Clone for ActorError {
fn clone(&self) -> Self {
Self {
source: anyhow::anyhow!(self.source.to_string()),
request: self.request.clone(),
}
}
}
impl ActorError {
pub fn exit<E: Into<anyhow::Error>>(error: E) -> Self {
Self {
source: error.into(),
request: ActorRequest::Exit.into(),
}
}
pub fn exit_msg<E>(msg: E) -> Self
where
E: fmt::Display + fmt::Debug + Send + Sync + 'static,
{
Self {
source: anyhow::Error::msg(msg),
request: ActorRequest::Exit.into(),
}
}
pub fn aborted<E: Into<anyhow::Error>>(error: E) -> Self {
Self {
source: error.into(),
request: ActorRequest::Aborted.into(),
}
}
pub fn aborted_msg<E>(msg: E) -> Self
where
E: fmt::Display + fmt::Debug + Send + Sync + 'static,
{
Self {
source: anyhow::Error::msg(msg),
request: ActorRequest::Aborted.into(),
}
}
pub fn restart<E: Into<anyhow::Error>, D: Into<Option<Duration>>>(error: E, after: D) -> Self {
Self {
source: error.into(),
request: ActorRequest::Restart(after.into()).into(),
}
}
pub fn restart_msg<E, D: Into<Option<Duration>>>(msg: E, after: D) -> Self
where
E: fmt::Display + fmt::Debug + Send + Sync + 'static,
{
Self {
source: anyhow::Error::msg(msg),
request: ActorRequest::Restart(after.into()).into(),
}
}
}