//! Sync (inter-thread communication) helpers use super::*; use std::{ sync::{ Arc, Weak, }, mem::{ self, MaybeUninit, }, ptr, fmt, error, }; use parking_lot::{ Condvar, Mutex, }; /// Send a single value across thread boundaries to a receiver. /// /// This is a sync implementation of `tokio::sync::oneshot`. pub mod oneshot { use super::*; /// Error when sending #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum SendError { /// The corresponding `Receiver` channel has been dropped. /// /// # Note /// This operation **cannot** be re-tried Closed, //TODO: Should we (or *can* we even?) have a `send_wait()` method? } /// Error when receiving #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum RecvError { /// The corresponding `Sender` channel has been dropped. /// /// # Note /// This operation **cannot** be re-tried Closed, /// The `recv()` call timed out before a value was sent. /// /// This operation can be re-tried Timeout, /// The `recv()` call was cancelled by a `StopToken` before a value was sent. /// /// This operation can be re-tried //TODO: Maybe merge this and `Timeout`? Cancelled, } //TODO: Add impl Send/RecvError: `fn can_retry(&self) -> bool` impl fmt::Display for SendError { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("send error") // TODO: Should we `match self` for detailed error messages here? } } impl fmt::Display for RecvError { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("recv error") // TODO: Should we `match self` for detailed error messages here? } } impl error::Error for SendError{} impl error::Error for RecvError{} impl error::Error for Error { #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { Some(match &self { Self::Recv(r) => r, Self::Send(s) => s, }) } } impl fmt::Display for Error { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("oneshot error") } } /// An error using the `oneshot` channel. #[derive(Debug)] pub enum Error { /// An error regarding the sending of a value. Send(SendError), /// An error regarding the receiving of a value. Recv(RecvError), } impl From for Error { #[inline] fn from(from: SendError) -> Self { Self::Send(from) } } impl From for Error { #[inline] fn from(from: RecvError) -> Self { Self::Recv(from) } } //TODO: impl fmt::Display error::Error for Try*Error[]... impl fmt::Display for TrySendError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "send error (T = {})", std::any::type_name::()) } } impl fmt::Display for TryRecvError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "recv error (T = {})", std::any::type_name::()) } } impl error::Error for TryRecvError where T: fmt::Debug { #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { Some(&self.0) } } impl error::Error for TrySendError where T: fmt::Debug { #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { Some(&self.0) } } impl fmt::Display for TryError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "oneshot error (T = {})", std::any::type_name::()) } } impl error::Error for TryError where T: fmt::Debug { #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { Some(&self.0) } } //TODO: XXX: We might also want explicit `Debug` impls for all `Try*Error`s, since `T` is irrelevent to the `Error` part. /// Error when attempting to send a value using a `try_` function. /// /// The `Sender` object that originated this is stored in this object for a re-try of the operation. #[derive(Debug)] pub struct TrySendError(SendError, Sender); /// Error when attempting to receive a value using a `try_` function. /// /// The `Receiver` object that originated this is stored in this object for a re-try of the operation. #[derive(Debug)] pub struct TryRecvError(RecvError, Receiver); /// An error when attempting a oneshot function using a consuming `try_` function. /// /// The `Sender`/`Receiver` object(s) that originated this error are stored in this object for a re-try of the operation. #[derive(Debug)] pub struct TryError(Error, (Option>, Option>)); //TODO: Make a `feature=unstable` version that is allocator-aware *and* re-uses the same allocation for both `Arc` creations (e.g. C++ polymorphic allocator; `bumpalo` or another simple implementation `Sync` bump-allocator would suffice.) /// Oneshot sender. /// /// Sends one value of `T` to a corresponding `Receiver`, if it is still alive. #[derive(Debug)] pub struct Sender { /// The value to write (`Sender`) to / read (`Receiver`) from. /// /// Write is bound to `send.notify_one()`, read is bound to `send.wait()`. /// # Ownership /// /// Note that `Receiver` has a `Weak` variant to hold this. It will fail to read if it cannot upgrade. /// If this slot is unique, then `send`s should fast-fail as there is no corresponding `Receiver` anyway. value: Weak>>, /// Sends a signal to the receiver to read from `value`. /// /// # Ownership /// If this weak-ptr cannot be upgraded, then the `Receiver` ascosiated with this instance *cannot* be waiting on it, and therefore sending should fast-fail //XXX: Is this order of Sender: `Arc, Weak`, Receiver: `Weak, Arc` correct? Check and think about it before proceeding pls... //NOTE: It **is correct** to be this order. send: Arc, } /// Oneshot receiver. /// /// Receive one value of `T` from a corresponding `Sender`, if it is still alive. #[derive(Debug)] pub struct Receiver { value: Arc>>, send: Weak, } }