From 6e185d24c5ae30ef498f2f2f5b5be8e0ff22e1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Laitl?= Date: Wed, 24 Feb 2021 18:31:07 +0100 Subject: [PATCH] Introduce own SendError for Recipient::send() functions This is to erase `M` generic parameter from Recipient method return types, which may help me with #11. Does a bit of what #20 wants to do, consider this commit temporary until I can rebase. --- src/lib.rs | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2a97b00..2d956dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ //! ``` //! -use crossbeam::channel::{self, select, Receiver, SendError, Sender, TrySendError}; +use crossbeam::channel::{self, select, Receiver, Sender}; use log::*; use parking_lot::{Mutex, RwLock}; use std::{fmt, ops::Deref, sync::Arc, thread, time::Duration}; @@ -86,6 +86,32 @@ impl fmt::Display for ActorError { impl std::error::Error for ActorError {} +/// Reasons why sending a message to an actor can fail. +#[derive(Debug)] +pub enum SendError { + /// The chanel's capacity is full. + Full, + /// The recipient of the message no longer exists. + Disconnected, +} + +impl fmt::Display for SendError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +impl std::error::Error for SendError {} + +impl From> for SendError { + fn from(orig: channel::TrySendError) -> Self { + match orig { + channel::TrySendError::Full(_) => Self::Full, + channel::TrySendError::Disconnected(_) => Self::Disconnected, + } + } +} + /// Systems are responsible for keeping track of their spawned actors, and managing /// their lifecycles appropriately. /// @@ -619,16 +645,16 @@ impl Clone for Recipient { impl Recipient { /// Non-blocking call to send a message. Use this if you need to react when /// the channel is full. - pub fn try_send>(&self, message: N) -> Result<(), TrySendError> { - self.message_tx.try_send(message.into()) + pub fn try_send>(&self, message: N) -> Result<(), SendError> { + self.message_tx.try_send(message.into()).map_err(SendError::from) } /// Non-blocking call to send a message. Use this if there is nothing you can /// do when the channel is full. The method still logs a warning for you in /// that case. - pub fn send>(&self, message: N) -> Result<(), TrySendError> { + pub fn send>(&self, message: N) -> Result<(), SendError> { let result = self.try_send(message.into()); - if let Err(TrySendError::Full(_)) = &result { + if let Err(SendError::Full) = &result { trace!("[{}] dropped message (channel bloat)", self.actor_name); return Ok(()); } @@ -644,7 +670,7 @@ impl Recipient { /// Non-blocking call to send a message. Use if you expect the channel to be /// frequently full (slow consumer), but would still like to be notified if a /// different error occurs (e.g. disconnection). - pub fn send_if_not_full>(&self, message: N) -> Result<(), TrySendError> { + pub fn send_if_not_full>(&self, message: N) -> Result<(), SendError> { if self.remaining_capacity().unwrap_or(usize::max_value()) > 1 { return self.send(message); } @@ -652,8 +678,8 @@ impl Recipient { Ok(()) } - pub fn stop(&self) -> Result<(), SendError<()>> { - self.control_tx.send(Control::Stop).map_err(|_| SendError(())) + pub fn stop(&self) -> Result<(), SendError> { + self.control_tx.send(Control::Stop).map_err(|_| SendError::Disconnected) } // TODO(ryo): Properly support the concept of priority channels.