use std::{future::Future, pin::Pin, sync::Arc};
use crate::{
actors::{Actor, Address, Handler},
message::Message,
};
trait MailboxSender<T: Message>: Send + Sync {
fn send<'a>(&'a self, msg: T) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
fn try_send(&self, msg: T);
}
impl<A, T> MailboxSender<T> for Address<A>
where
A: 'static + Actor + Send + Handler<T>,
T: Message,
{
fn send<'a>(&'a self, msg: T) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(Address::send(self, msg))
}
fn try_send(&self, msg: T) {
Address::try_send(self, msg);
}
}
pub struct Mailbox<T: Message> {
sender: Arc<dyn MailboxSender<T>>,
}
impl<T: Message> Clone for Mailbox<T> {
fn clone(&self) -> Self {
Self {
sender: Arc::clone(&self.sender),
}
}
}
impl<T: Message> std::fmt::Debug for Mailbox<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Mailbox").finish_non_exhaustive()
}
}
impl<T: Message> Mailbox<T> {
pub async fn send(&self, msg: T) {
self.sender.send(msg).await
}
pub fn try_send(&self, msg: T) {
self.sender.try_send(msg);
}
}
impl<A> Address<A>
where
A: 'static + Actor + Send,
{
pub fn into_mailbox<T>(self) -> Mailbox<T>
where
A: Handler<T>,
T: Message,
{
Mailbox {
sender: Arc::new(self),
}
}
}
impl<A, T> From<Address<A>> for Mailbox<T>
where
A: 'static + Actor + Send + Handler<T>,
T: Message,
{
fn from(address: Address<A>) -> Self {
address.into_mailbox()
}
}
#[cfg(test)]
mod tests {
use crate::{executor::Context, Executor};
use super::*;
struct Ping;
struct Pong;
struct MyActor;
impl Actor for MyActor {}
impl Handler<Ping> for MyActor {
async fn handle(&mut self, _msg: Ping, _ctx: &Context<Self>) {}
}
impl Handler<Pong> for MyActor {
async fn handle(&mut self, _msg: Pong, _ctx: &Context<Self>) {}
}
#[test]
fn into_mailbox_compiles() {
let (_executor, address) = Executor::new(MyActor);
let _mailbox: Mailbox<Ping> = address.into_mailbox();
}
#[test]
fn from_address_compiles() {
let (_executor, address) = Executor::new(MyActor);
let _mailbox: Mailbox<Pong> = Mailbox::from(address);
}
#[test]
fn mailbox_is_clone() {
let (_executor, address) = Executor::new(MyActor);
let mailbox: Mailbox<Ping> = address.into_mailbox();
let _ = mailbox.clone();
}
#[test]
fn mailbox_is_debug() {
let (_executor, address) = Executor::new(MyActor);
let mailbox: Mailbox<Ping> = address.into_mailbox();
let _ = format!("{:?}", mailbox);
}
}