blob: 1fd0de1eed8b195095cc42fb9e082cec333271b4 [file] [log] [blame] [edit]
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`](crate::Sender::send) if the corresponding [`Receiver`](crate::Receiver)
/// has already been dropped.
///
/// The message that could not be sent can be retreived again with [`SendError::into_inner`].
pub struct SendError<T> {
channel_ptr: NonNull<Channel<T>>,
}
unsafe impl<T: Send> Send for SendError<T> {}
unsafe impl<T: Sync> Sync for SendError<T> {}
impl<T> SendError<T> {
/// # 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<Channel<T>>) -> 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<T> = 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<T> Drop for SendError<T> {
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<T> fmt::Display for SendError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"sending on a closed channel".fmt(f)
}
}
impl<T> fmt::Debug for SendError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SendError<{}>(_)", stringify!(T))
}
}
#[cfg(feature = "std")]
impl<T> std::error::Error for SendError<T> {}
/// An error returned from the blocking [`Receiver::recv`](crate::Receiver::recv) method.
///
/// The receive operation can only fail if the corresponding [`Sender`](crate::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 failing to receive a message in the non-blocking
/// [`Receiver::try_recv`](crate::Receiver::try_recv).
#[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 failing to receive a message in
/// [`Receiver::recv_timeout`](crate::Receiver::recv_timeout).
#[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 {}