use std::{
cell::RefCell,
collections::VecDeque,
rc::{Rc, Weak},
};
use anyhow::{anyhow, Error};
use thiserror::Error;
use crate::{Id, World};
pub struct Mailbox<M> {
inner: Rc<RefCell<MailboxInner<M>>>,
}
impl<M> Default for Mailbox<M> {
fn default() -> Self {
let inner = MailboxInner {
queue: VecDeque::new(),
notify: None,
};
Self {
inner: Rc::new(RefCell::new(inner)),
}
}
}
impl<M> Clone for Mailbox<M> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
struct MailboxInner<M> {
queue: VecDeque<M>,
notify: Option<Id>,
}
impl<M> Mailbox<M> {
pub fn register(&self, id: Id) {
self.inner.borrow_mut().notify = Some(id);
}
pub fn next(&self) -> Option<M> {
self.inner.borrow_mut().queue.pop_front()
}
pub fn sender(&self) -> Sender<M> {
Sender {
inner: Rc::downgrade(&self.inner),
}
}
}
pub struct Sender<M> {
inner: Weak<RefCell<MailboxInner<M>>>,
}
impl<M> Sender<M> {
pub fn send(&self, world: &mut World, message: M) -> Result<(), SendError> {
let Some(inner) = self.inner.upgrade() else {
return Err(anyhow!("mailbox closed").into())
};
let mut inner = inner.borrow_mut();
inner.queue.push_back(message);
if let Some(notify) = inner.notify {
world.notify(notify);
}
Ok(())
}
}
impl<M> Clone for Sender<M> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
#[derive(Error, Debug)]
#[error("sending message failed")]
pub struct SendError {
#[from]
source: Error,
}