use thiserror::Error;
use tokio::sync::{mpsc, oneshot};
pub mod callback;
pub mod notification_channel;
pub mod plain;
#[derive(Debug, PartialEq, Eq, Error)]
pub enum Error {
#[error("Mailbox is stopped")]
MailboxStopped,
}
pub type Result<T> = std::result::Result<T, Error>;
fn ignore_error<E>(_r: std::result::Result<(), E>) {}
pub struct ReplyChannel<T> {
sender: oneshot::Sender<T>,
}
impl<T> ReplyChannel<T> {
pub fn reply(self, val: T) {
ignore_error(self.sender.send(val));
}
}
impl<T> std::fmt::Debug for ReplyChannel<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<ReplyChannel of {}>", std::any::type_name::<T>())
}
}
pub struct RequestReplyChannel<Request, Reply> {
sender: mpsc::UnboundedSender<(Request, ReplyChannel<Reply>)>,
}
impl<Request, Reply> Clone for RequestReplyChannel<Request, Reply> {
fn clone(&self) -> Self {
Self {
sender: self.sender.clone(),
}
}
}
#[derive(Debug, Error)]
pub enum RequestReplyError {
#[error("The receiver was dropped before the request could be sent")]
ReceiverDropper,
#[error("The reply channel was dropped while waiting for a reply")]
ReplyChannelDropped,
}
impl<Request, Reply> RequestReplyChannel<Request, Reply> {
pub fn new() -> (
Self,
mpsc::UnboundedReceiver<(Request, ReplyChannel<Reply>)>,
) {
let (tx, rx) = mpsc::unbounded_channel();
(Self { sender: tx }, rx)
}
pub async fn request(&self, request: Request) -> std::result::Result<Reply, RequestReplyError> {
let (tx, rx) = oneshot::channel();
let reply_channel = ReplyChannel { sender: tx };
self.sender
.send((request, reply_channel))
.map_err(|_| RequestReplyError::ReceiverDropper)?;
rx.await.map_err(|_| RequestReplyError::ReplyChannelDropped)
}
}