use std::fmt::Display;
use crate::ActorName;
pub type ActorProcessingErr = Box<dyn std::error::Error + Send + Sync + 'static>;
#[derive(Debug)] pub enum SpawnErr {
StartupPanic(ActorProcessingErr),
StartupCancelled,
ActorAlreadyStarted,
ActorAlreadyRegistered(ActorName),
}
impl std::error::Error for SpawnErr {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self {
Self::StartupPanic(inner) => Some(inner.as_ref()),
_ => None,
}
}
}
impl Display for SpawnErr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::StartupPanic(panic_msg) => {
if f.alternate() {
write!(f, "Actor panicked during startup '{panic_msg:#}'")
} else {
write!(f, "Actor panicked during startup '{panic_msg}'")
}
}
Self::StartupCancelled => {
write!(
f,
"Actor failed to startup due to processing task being cancelled"
)
}
Self::ActorAlreadyStarted => {
write!(f, "Actor cannot be re-started more than once")
}
Self::ActorAlreadyRegistered(actor_name) => {
write!(
f,
"Actor '{actor_name}' is already registered in the actor registry"
)
}
}
}
}
impl From<crate::registry::ActorRegistryErr> for SpawnErr {
fn from(value: crate::registry::ActorRegistryErr) -> Self {
match value {
crate::registry::ActorRegistryErr::AlreadyRegistered(actor_name) => {
SpawnErr::ActorAlreadyRegistered(actor_name)
}
}
}
}
#[derive(Debug)]
pub enum ActorErr {
Cancelled,
Panic(ActorProcessingErr),
}
impl std::error::Error for ActorErr {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self {
Self::Panic(inner) => Some(inner.as_ref()),
_ => None,
}
}
}
impl Display for ActorErr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Panic(panic_msg) => {
if f.alternate() {
write!(f, "Actor panicked '{panic_msg:#}'")
} else {
write!(f, "Actor panicked '{panic_msg}'")
}
}
Self::Cancelled => {
write!(f, "Actor operation cancelled")
}
}
}
}
pub enum MessagingErr<T> {
SendErr(T),
ChannelClosed,
InvalidActorType,
}
impl<T> MessagingErr<T> {
pub fn map<F, U>(self, mapper: F) -> MessagingErr<U>
where
F: FnOnce(T) -> U,
{
match self {
MessagingErr::SendErr(err) => MessagingErr::SendErr(mapper(err)),
MessagingErr::ChannelClosed => MessagingErr::ChannelClosed,
MessagingErr::InvalidActorType => MessagingErr::InvalidActorType,
}
}
}
unsafe impl<T> Sync for MessagingErr<T> {}
impl<T> std::fmt::Debug for MessagingErr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::SendErr(_) => write!(f, "SendErr"),
Self::ChannelClosed => write!(f, "RecvErr"),
Self::InvalidActorType => write!(f, "InvalidActorType"),
}
}
}
impl<T> std::error::Error for MessagingErr<T> {}
impl<T> From<tokio::sync::mpsc::error::SendError<T>> for MessagingErr<T> {
fn from(e: tokio::sync::mpsc::error::SendError<T>) -> Self {
Self::SendErr(e.0)
}
}
impl<T> From<tokio::sync::mpsc::error::TrySendError<T>> for MessagingErr<T> {
fn from(e: tokio::sync::mpsc::error::TrySendError<T>) -> Self {
match e {
tokio::sync::mpsc::error::TrySendError::Closed(c) => Self::SendErr(c),
tokio::sync::mpsc::error::TrySendError::Full(c) => Self::SendErr(c),
}
}
}
impl<T> Display for MessagingErr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ChannelClosed => {
write!(f, "Messaging failed because channel is closed")
}
Self::InvalidActorType => {
write!(f, "Messaging failed due to the provided actor type not matching the actor's properties")
}
Self::SendErr(_) => {
write!(f, "Messaging failed to enqueue the message to the specified actor, the actor is likely terminated")
}
}
}
}
pub enum RactorErr<T> {
Spawn(SpawnErr),
Messaging(MessagingErr<T>),
Actor(ActorErr),
Timeout,
}
impl<T> RactorErr<T> {
pub fn has_message(&self) -> bool {
matches!(self, Self::Messaging(MessagingErr::SendErr(_)))
}
pub fn try_get_message(self) -> Option<T> {
if let Self::Messaging(MessagingErr::SendErr(msg)) = self {
Some(msg)
} else {
None
}
}
pub fn map<F, U>(self, mapper: F) -> RactorErr<U>
where
F: FnOnce(T) -> U,
{
match self {
RactorErr::Spawn(err) => RactorErr::Spawn(err),
RactorErr::Messaging(err) => RactorErr::Messaging(err.map(mapper)),
RactorErr::Actor(err) => RactorErr::Actor(err),
RactorErr::Timeout => RactorErr::Timeout,
}
}
}
impl<T> std::fmt::Debug for RactorErr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Messaging(m) => write!(f, "Messaging({:?})", m),
Self::Actor(a) => write!(f, "Actor({:?})", a),
Self::Spawn(s) => write!(f, "Spawn({:?})", s),
Self::Timeout => write!(f, "Timeout"),
}
}
}
impl<T> std::error::Error for RactorErr<T> {}
impl<T> From<SpawnErr> for RactorErr<T> {
fn from(value: SpawnErr) -> Self {
RactorErr::Spawn(value)
}
}
impl<T> From<MessagingErr<T>> for RactorErr<T> {
fn from(value: MessagingErr<T>) -> Self {
RactorErr::Messaging(value)
}
}
impl<T> From<ActorErr> for RactorErr<T> {
fn from(value: ActorErr) -> Self {
RactorErr::Actor(value)
}
}
impl<T, TResult> From<crate::rpc::CallResult<TResult>> for RactorErr<T> {
fn from(value: crate::rpc::CallResult<TResult>) -> Self {
match value {
crate::rpc::CallResult::SenderError => {
RactorErr::Messaging(MessagingErr::ChannelClosed)
}
crate::rpc::CallResult::Timeout => RactorErr::Timeout,
_ => panic!("A successful `CallResult` cannot be mapped to a `RactorErr`"),
}
}
}
impl<T> std::fmt::Display for RactorErr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Actor(actor_err) => {
if f.alternate() {
write!(f, "{actor_err:#}")
} else {
write!(f, "{actor_err}")
}
}
Self::Messaging(messaging_err) => {
if f.alternate() {
write!(f, "{messaging_err:#}")
} else {
write!(f, "{messaging_err}")
}
}
Self::Spawn(spawn_err) => {
if f.alternate() {
write!(f, "{spawn_err:#}")
} else {
write!(f, "{spawn_err}")
}
}
Self::Timeout => {
write!(f, "timeout")
}
}
}
}