use super::{dealloc, Channel}; use core::fmt; use core::mem; use core::ptr::NonNull; /// An error returned when trying to send on a closed channel. Returned from /// [`Sender::send`] if the corresponding [`Receiver`] has already been dropped. /// /// The message that could not be sent can be retreived again with [`SendError::into_inner`]. pub struct SendError { channel_ptr: NonNull>, } unsafe impl Send for SendError {} unsafe impl Sync for SendError {} impl SendError { /// # Safety /// /// By calling this function, the caller semantically transfers ownership of the /// channel's resources to the created `SendError`. Thus the caller must ensure that the /// pointer is not used in a way which would violate this ownership transfer. Moreover, /// the caller must assert that the channel contains a valid, initialized message. pub(crate) const unsafe fn new(channel_ptr: NonNull>) -> Self { Self { channel_ptr } } /// Consumes the error and returns the message that failed to be sent. #[inline] pub fn into_inner(self) -> T { let channel_ptr = self.channel_ptr; // Don't run destructor if we consumed ourselves. Freeing happens here. mem::forget(self); // SAFETY: we have ownership of the channel let channel: &Channel = unsafe { channel_ptr.as_ref() }; // SAFETY: we know that the message is initialized according to the safety requirements of // `new` let message = unsafe { channel.take_message() }; // SAFETY: we own the channel unsafe { dealloc(channel_ptr) }; message } /// Get a reference to the message that failed to be sent. #[inline] pub fn as_inner(&self) -> &T { unsafe { self.channel_ptr.as_ref().message().assume_init_ref() } } } impl Drop for SendError { fn drop(&mut self) { // SAFETY: we have ownership of the channel and require that the message is initialized // upon construction unsafe { self.channel_ptr.as_ref().drop_message(); dealloc(self.channel_ptr); } } } impl fmt::Display for SendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "sending on a closed channel".fmt(f) } } impl fmt::Debug for SendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "SendError<{}>(_)", stringify!(T)) } } #[cfg(feature = "std")] impl std::error::Error for SendError {} /// An error returned from the indefinitely blocking recv functions on a [`Receiver`]. /// /// The recv operation can only fail if the corresponding [`Sender`] was dropped before sending /// any message. Or if a message has already been sent and received on the channel. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct RecvError; impl fmt::Display for RecvError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "receiving on a closed channel".fmt(f) } } #[cfg(feature = "std")] impl std::error::Error for RecvError {} /// An error returned when trying a non blocking receive on a [`Receiver`]. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum TryRecvError { /// The channel is still open, but there was no message present in it. Empty, /// The channel is closed. Either the sender was dropped before sending any message, or the /// message has already been extracted from the receiver. Disconnected, } impl fmt::Display for TryRecvError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let msg = match self { TryRecvError::Empty => "receiving on an empty channel", TryRecvError::Disconnected => "receiving on a closed channel", }; msg.fmt(f) } } #[cfg(feature = "std")] impl std::error::Error for TryRecvError {} /// An error returned when trying a time limited blocking receive on a [`Receiver`]. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum RecvTimeoutError { /// No message arrived on the channel before the timeout was reached. The channel is still open. Timeout, /// The channel is closed. Either the sender was dropped before sending any message, or the /// message has already been extracted from the receiver. Disconnected, } impl fmt::Display for RecvTimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let msg = match self { RecvTimeoutError::Timeout => "timed out waiting on channel", RecvTimeoutError::Disconnected => "channel is empty and sending half is closed", }; msg.fmt(f) } } #[cfg(feature = "std")] impl std::error::Error for RecvTimeoutError {}