use std::{sync::mpsc, time::Duration};
use reovim_arch::sync::Mutex;
pub struct Sender<T>(mpsc::Sender<T>);
impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
pub struct Receiver<T>(mpsc::Receiver<T>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendError<T>(pub T);
impl<T> std::fmt::Display for SendError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "sending on a closed channel")
}
}
impl<T: std::fmt::Debug> std::error::Error for SendError<T> {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RecvError;
impl std::fmt::Display for RecvError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "receiving on a closed channel")
}
}
impl std::error::Error for RecvError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TryRecvError {
Empty,
Disconnected,
}
impl std::fmt::Display for TryRecvError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Empty => write!(f, "channel is empty"),
Self::Disconnected => write!(f, "channel is disconnected"),
}
}
}
impl std::error::Error for TryRecvError {}
impl<T> Sender<T> {
pub fn send(&self, value: T) -> Result<(), SendError<T>> {
self.0.send(value).map_err(|e| SendError(e.0))
}
}
impl<T> std::fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Sender").finish_non_exhaustive()
}
}
impl<T> Receiver<T> {
pub fn recv(&self) -> Result<T, RecvError> {
self.0.recv().map_err(|_| RecvError)
}
pub fn try_recv(&self) -> Result<T, TryRecvError> {
self.0.try_recv().map_err(|e| match e {
mpsc::TryRecvError::Empty => TryRecvError::Empty,
mpsc::TryRecvError::Disconnected => TryRecvError::Disconnected,
})
}
pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvError> {
self.0.recv_timeout(timeout).map_err(|_| RecvError)
}
pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
self.0.iter()
}
pub fn try_iter(&self) -> impl Iterator<Item = T> + '_ {
self.0.try_iter()
}
}
impl<T> std::fmt::Debug for Receiver<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Receiver").finish_non_exhaustive()
}
}
#[must_use]
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let (tx, rx) = mpsc::channel();
(Sender(tx), Receiver(rx))
}
pub struct BoundedSender<T>(mpsc::SyncSender<T>);
impl<T> Clone for BoundedSender<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
pub struct BoundedReceiver<T>(mpsc::Receiver<T>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TrySendError<T> {
Full(T),
Disconnected(T),
}
impl<T> std::fmt::Display for TrySendError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Full(_) => write!(f, "channel is full"),
Self::Disconnected(_) => write!(f, "channel is disconnected"),
}
}
}
impl<T: std::fmt::Debug> std::error::Error for TrySendError<T> {}
impl<T> BoundedSender<T> {
pub fn send(&self, value: T) -> Result<(), SendError<T>> {
self.0.send(value).map_err(|e| SendError(e.0))
}
pub fn try_send(&self, value: T) -> Result<(), TrySendError<T>> {
self.0.try_send(value).map_err(|e| match e {
mpsc::TrySendError::Full(v) => TrySendError::Full(v),
mpsc::TrySendError::Disconnected(v) => TrySendError::Disconnected(v),
})
}
}
impl<T> std::fmt::Debug for BoundedSender<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BoundedSender").finish_non_exhaustive()
}
}
impl<T> BoundedReceiver<T> {
pub fn recv(&self) -> Result<T, RecvError> {
self.0.recv().map_err(|_| RecvError)
}
#[cfg_attr(coverage_nightly, coverage(off))]
pub fn try_recv(&self) -> Result<T, TryRecvError> {
self.0.try_recv().map_err(|e| match e {
mpsc::TryRecvError::Empty => TryRecvError::Empty,
mpsc::TryRecvError::Disconnected => TryRecvError::Disconnected,
})
}
pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvError> {
self.0.recv_timeout(timeout).map_err(|_| RecvError)
}
pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
self.0.iter()
}
pub fn try_iter(&self) -> impl Iterator<Item = T> + '_ {
self.0.try_iter()
}
}
impl<T> std::fmt::Debug for BoundedReceiver<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BoundedReceiver").finish_non_exhaustive()
}
}
#[must_use]
pub fn bounded<T>(capacity: usize) -> (BoundedSender<T>, BoundedReceiver<T>) {
let (tx, rx) = mpsc::sync_channel(capacity);
(BoundedSender(tx), BoundedReceiver(rx))
}
pub struct OneshotSender<T> {
inner: Mutex<Option<mpsc::SyncSender<T>>>,
}
pub struct OneshotReceiver<T>(mpsc::Receiver<T>);
impl<T> OneshotSender<T> {
#[cfg_attr(coverage_nightly, coverage(off))]
pub fn send(self, value: T) -> Result<(), T> {
let sender = self.inner.lock().take();
match sender {
Some(tx) => tx.send(value).map_err(|e| e.0),
None => Err(value),
}
}
#[must_use]
pub fn is_connected(&self) -> bool {
self.inner.lock().is_some()
}
}
impl<T> std::fmt::Debug for OneshotSender<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OneshotSender")
.field("connected", &self.is_connected())
.finish()
}
}
impl<T> OneshotReceiver<T> {
pub fn recv(self) -> Result<T, RecvError> {
self.0.recv().map_err(|_| RecvError)
}
pub fn try_recv(&self) -> Result<T, TryRecvError> {
self.0.try_recv().map_err(|e| match e {
mpsc::TryRecvError::Empty => TryRecvError::Empty,
mpsc::TryRecvError::Disconnected => TryRecvError::Disconnected,
})
}
pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvError> {
self.0.recv_timeout(timeout).map_err(|_| RecvError)
}
}
impl<T> std::fmt::Debug for OneshotReceiver<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OneshotReceiver").finish_non_exhaustive()
}
}
#[must_use]
pub fn oneshot<T>() -> (OneshotSender<T>, OneshotReceiver<T>) {
let (tx, rx) = mpsc::sync_channel(1);
(
OneshotSender {
inner: Mutex::new(Some(tx)),
},
OneshotReceiver(rx),
)
}