use core::fmt::{Formatter, Write};
use kameo::{
Actor,
actor::{ActorRef, WeakActorRef},
error::SendError,
};
pub(crate) trait ResultExt {
type T;
fn with_actor_info(self, aref: impl Into<ActorInfo>) -> Result<Self::T, Error>;
}
impl<T, E> ResultExt for Result<T, E>
where
E: Into<Error>,
{
type T = T;
fn with_actor_info(self, aref: impl Into<ActorInfo>) -> Result<T, Error> {
self.map_err(|e| e.into().with_actor_info(aref))
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Error {
pub kind: ErrorKind,
pub message_ty: Option<&'static str>,
pub target_actor: Option<ActorInfo>,
}
impl Error {
pub fn with_actor_info(self, aref: impl Into<ActorInfo>) -> Self {
Self {
target_actor: Some(aref.into()),
..self
}
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
if let Some(ty) = self.message_ty {
write!(f, "sending {ty}")?;
if self.target_actor.is_some() {
f.write_char(' ')?;
}
}
if let Some(actor) = &self.target_actor {
write!(f, "{actor}")?;
}
if self.message_ty.is_some() || self.target_actor.is_some() {
f.write_str(": ")?;
}
self.kind.fmt(f)
}
}
impl core::error::Error for Error {}
impl<M, E> From<SendError<M, E>> for Error {
fn from(err: SendError<M, E>) -> Self {
Self {
kind: err.into(),
message_ty: Some(core::any::type_name::<M>()),
target_actor: None,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ActorInfo {
pub ty: &'static str,
pub id: kameo::actor::ActorId,
}
impl<A> From<&ActorRef<A>> for ActorInfo
where
A: Actor,
{
fn from(aref: &ActorRef<A>) -> Self {
Self {
ty: core::any::type_name::<A>(),
id: aref.id(),
}
}
}
impl<A> From<ActorRef<A>> for ActorInfo
where
A: Actor,
{
fn from(aref: ActorRef<A>) -> Self {
Self::from(&aref)
}
}
impl<A> From<&WeakActorRef<A>> for ActorInfo
where
A: Actor,
{
fn from(aref: &WeakActorRef<A>) -> Self {
Self {
ty: core::any::type_name::<A>(),
id: aref.id(),
}
}
}
impl<A> From<WeakActorRef<A>> for ActorInfo
where
A: Actor,
{
fn from(aref: WeakActorRef<A>) -> Self {
Self::from(&aref)
}
}
impl core::fmt::Display for ActorInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{}({})", self.ty, self.id)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ErrorKind {
ActorGone,
ReplyErr,
MailboxFull,
Timeout,
}
impl core::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::ActorGone => write!(f, "expected actor is unreachable"),
Self::ReplyErr => write!(f, "actor replied with an error"),
Self::MailboxFull => write!(f, "actor's mailbox was full"),
Self::Timeout => write!(f, "operation timed out"),
}
}
}
impl<M, E> From<SendError<M, E>> for ErrorKind {
fn from(err: SendError<M, E>) -> Self {
match err {
SendError::ActorNotRunning(_) | SendError::ActorStopped => ErrorKind::ActorGone,
SendError::HandlerError(_) => ErrorKind::ReplyErr,
SendError::MailboxFull(..) => ErrorKind::MailboxFull,
SendError::Timeout(_) => ErrorKind::Timeout,
}
}
}