use tokio::sync::{mpsc, oneshot};
use crate::actor::{Actor, ActorEnvelope};
use crate::error::{AskError, SendError, TrySendError};
use crate::types::{ActorId, ActorStatusInfo, Envelope, StopReason, SystemMessage};
#[derive(Debug)]
pub struct ActorHandle<A: Actor> {
id: ActorId,
tx: mpsc::Sender<ActorEnvelope<A>>,
system_tx: mpsc::Sender<SystemMessage>,
mailbox_capacity: usize,
}
impl<A: Actor> Clone for ActorHandle<A> {
fn clone(&self) -> Self {
Self {
id: self.id.clone(),
tx: self.tx.clone(),
system_tx: self.system_tx.clone(),
mailbox_capacity: self.mailbox_capacity,
}
}
}
impl<A: Actor> PartialEq for ActorHandle<A> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<A: Actor> Eq for ActorHandle<A> {}
impl<A: Actor> std::hash::Hash for ActorHandle<A> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl<A: Actor> ActorHandle<A> {
pub(crate) fn new(
id: ActorId,
tx: mpsc::Sender<ActorEnvelope<A>>,
system_tx: mpsc::Sender<SystemMessage>,
mailbox_capacity: usize,
) -> Self {
Self {
id,
tx,
system_tx,
mailbox_capacity,
}
}
pub(crate) fn system_tx(&self) -> mpsc::Sender<SystemMessage> {
self.system_tx.clone()
}
pub fn id(&self) -> &ActorId {
&self.id
}
pub fn mailbox_capacity(&self) -> usize {
self.mailbox_capacity
}
pub fn mailbox_len(&self) -> usize {
self.mailbox_capacity - self.tx.capacity()
}
pub fn mailbox_available(&self) -> usize {
self.tx.capacity()
}
pub fn is_alive(&self) -> bool {
!self.tx.is_closed()
}
pub async fn notify(&self, msg: A::Message) -> Result<(), SendError> {
self.tx
.send(Envelope::Message {
payload: msg,
responder: None,
})
.await
.map_err(|_| SendError::Closed)
}
pub fn try_notify(&self, msg: A::Message) -> Result<(), TrySendError> {
self.tx
.try_send(Envelope::Message {
payload: msg,
responder: None,
})
.map_err(|err| match err {
mpsc::error::TrySendError::Full(_) => TrySendError::Full,
mpsc::error::TrySendError::Closed(_) => TrySendError::Closed,
})
}
pub async fn send(&self, msg: A::Message) -> Result<A::Response, AskError> {
let (tx, rx) = oneshot::channel();
self.tx
.send(Envelope::Message {
payload: msg,
responder: Some(tx),
})
.await
.map_err(|_| AskError::Closed)?;
match rx.await.map_err(|_| AskError::ResponseDropped)? {
Ok(resp) => Ok(resp),
Err(err) => Err(AskError::Actor(err)),
}
}
pub async fn stop(&self, reason: StopReason) -> Result<(), SendError> {
self.system_tx
.send(SystemMessage::Stop(reason))
.await
.map_err(|_| SendError::Closed)
}
pub async fn get_status(&self) -> Result<ActorStatusInfo, AskError> {
let (tx, rx) = oneshot::channel();
self.system_tx
.send(SystemMessage::GetStatus(tx))
.await
.map_err(|_| AskError::Closed)?;
rx.await.map_err(|_| AskError::ResponseDropped)
}
}