use crate::mailbox::SendError;
use derive_more::Debug;
use std::time::Duration;
use thiserror::Error;
#[derive(Debug)]
pub struct ReplyTo<R> {
#[debug(skip)]
send_reply: Box<dyn FnOnce(R) + Send>,
}
impl<R> ReplyTo<R> {
pub fn reply(self, reply: R) {
(self.send_reply)(reply);
}
pub(crate) fn new<F>(send_reply: F) -> Self
where
F: FnOnce(R) + Send + 'static,
{
Self {
send_reply: Box::new(send_reply),
}
}
}
#[derive(Debug, Error)]
pub enum AskError {
#[error("mailbox full")]
MailboxFull,
#[error("actor terminated")]
ActorTerminated,
#[error("no reply")]
NoReply,
#[error("no reply within {0:?}")]
Timeout(Duration),
}
impl From<SendError> for AskError {
fn from(error: SendError) -> Self {
match error {
SendError::MailboxFull(_) => Self::MailboxFull,
SendError::ActorTerminated(_) => Self::ActorTerminated,
}
}
}
#[cfg(test)]
mod tests {
use crate::ReplyTo;
use std::sync::mpsc;
#[test]
fn reply_invokes_the_sink_with_the_reply() {
let (reply_tx, reply_rx) = mpsc::channel();
let reply_to = ReplyTo::new(move |reply| reply_tx.send(reply).expect("reply is received"));
reply_to.reply(42);
assert_eq!(reply_rx.recv(), Ok(42));
}
#[test]
fn debug_skips_the_sink() {
struct NotDebug;
let reply_to = ReplyTo::new(|NotDebug| ());
assert!(format!("{reply_to:?}").starts_with("ReplyTo"));
}
}