Skip to content

Commit

Permalink
Introduce own SendError for Recipient::send() functions
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
strohel committed Feb 25, 2021
1 parent 120219b commit 6e185d2
Showing 1 changed file with 34 additions and 8 deletions.
42 changes: 34 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<M> From<channel::TrySendError<M>> for SendError {
fn from(orig: channel::TrySendError<M>) -> 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.
///
Expand Down Expand Up @@ -619,16 +645,16 @@ impl<M> Clone for Recipient<M> {
impl<M> Recipient<M> {
/// Non-blocking call to send a message. Use this if you need to react when
/// the channel is full.
pub fn try_send<N: Into<M>>(&self, message: N) -> Result<(), TrySendError<M>> {
self.message_tx.try_send(message.into())
pub fn try_send<N: Into<M>>(&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<N: Into<M>>(&self, message: N) -> Result<(), TrySendError<M>> {
pub fn send<N: Into<M>>(&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(());
}
Expand All @@ -644,16 +670,16 @@ impl<M> Recipient<M> {
/// 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<N: Into<M>>(&self, message: N) -> Result<(), TrySendError<M>> {
pub fn send_if_not_full<N: Into<M>>(&self, message: N) -> Result<(), SendError> {
if self.remaining_capacity().unwrap_or(usize::max_value()) > 1 {
return self.send(message);
}

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.
Expand Down

0 comments on commit 6e185d2

Please sign in to comment.