use core::fmt;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll, Waker};
use std::sync::Arc;
use concurrent_queue::{ConcurrentQueue, PopError, PushError};
use crate::compati::Mutex;
use crate::valtron::{QueueReadiness, QueueVacancyReadiness};
pub(crate) struct PipeInner<T> {
pub(crate) queue: Arc<ConcurrentQueue<T>>,
pub(crate) consumer_waker: Mutex<Option<Waker>>,
pub(crate) producer_waker: Mutex<Option<Waker>>,
}
impl<T> PipeInner<T> {
pub(crate) fn wake_consumer(&self) {
if let Some(waker) = self.consumer_waker.lock().unwrap().take() {
waker.wake();
}
}
pub(crate) fn wake_producer(&self) {
if let Some(waker) = self.producer_waker.lock().unwrap().take() {
waker.wake();
}
}
}
pub struct Pipe<T>(core::marker::PhantomData<T>);
impl<T> Pipe<T> {
pub const DEFAULT_DEPTH: usize = 4;
#[must_use]
pub fn new() -> (PipeSender<T>, PipeReceiver<T>) {
Self::with_depth(Self::DEFAULT_DEPTH)
}
#[must_use]
pub fn with_depth(depth: usize) -> (PipeSender<T>, PipeReceiver<T>) {
let inner = Arc::new(PipeInner {
queue: Arc::new(ConcurrentQueue::bounded(depth.max(1))),
consumer_waker: Mutex::new(None),
producer_waker: Mutex::new(None),
});
(
PipeSender {
inner: inner.clone(),
},
PipeReceiver { inner },
)
}
}
pub struct PipeSender<T> {
pub(crate) inner: Arc<PipeInner<T>>,
}
impl<T> Clone for PipeSender<T> {
fn clone(&self) -> Self {
Self { inner: self.inner.clone() }
}
}
impl<T> PipeSender<T> {
pub fn try_send(&self, item: T) -> Result<(), TrySendError<T>> {
match self.inner.queue.push(item) {
Ok(()) => {
self.inner.wake_consumer();
Ok(())
}
Err(PushError::Full(item)) => Err(TrySendError::Full(item)),
Err(PushError::Closed(item)) => Err(TrySendError::Closed(item)),
}
}
#[must_use = "futures do nothing unless awaited"]
pub fn send(&self, item: T) -> SendFuture<'_, T> {
SendFuture {
sender: self,
item: Some(item),
}
}
#[must_use]
pub fn vacancy(&self) -> QueueVacancyReadiness<T>
where
T: Send,
{
QueueVacancyReadiness::new(self.inner.queue.clone())
}
#[must_use]
pub fn is_full(&self) -> bool {
self.inner.queue.is_full()
}
#[must_use]
pub fn is_closed(&self) -> bool {
self.inner.queue.is_closed()
}
#[must_use]
pub fn len(&self) -> usize {
self.inner.queue.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.queue.is_empty()
}
#[must_use]
pub fn capacity(&self) -> usize {
self.inner
.queue
.capacity()
.expect("Pipe is always constructed bounded")
}
pub fn close(&self) -> bool {
let closed = self.inner.queue.close();
self.inner.wake_consumer();
closed
}
}
impl<T> Drop for PipeSender<T> {
fn drop(&mut self) {
self.inner.queue.close();
self.inner.wake_consumer();
}
}
pub struct SendFuture<'a, T> {
sender: &'a PipeSender<T>,
item: Option<T>,
}
impl<T> Unpin for SendFuture<'_, T> {}
impl<T> Future for SendFuture<'_, T> {
type Output = Result<(), SendError<T>>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let item = self
.item
.take()
.expect("SendFuture polled after completion");
match self.sender.inner.queue.push(item) {
Ok(()) => {
self.sender.inner.wake_consumer();
Poll::Ready(Ok(()))
}
Err(PushError::Closed(item)) => Poll::Ready(Err(SendError(item))),
Err(PushError::Full(item)) => {
*self.sender.inner.producer_waker.lock().unwrap() = Some(cx.waker().clone());
match self.sender.inner.queue.push(item) {
Ok(()) => {
self.sender.inner.wake_consumer();
Poll::Ready(Ok(()))
}
Err(PushError::Closed(item)) => Poll::Ready(Err(SendError(item))),
Err(PushError::Full(item)) => {
self.item = Some(item);
Poll::Pending
}
}
}
}
}
}
pub struct PipeReceiver<T> {
pub(crate) inner: Arc<PipeInner<T>>,
}
impl<T> Clone for PipeReceiver<T> {
fn clone(&self) -> Self {
Self { inner: self.inner.clone() }
}
}
impl<T> PipeReceiver<T> {
pub fn try_recv(&self) -> Result<T, TryRecvError> {
match self.inner.queue.pop() {
Ok(item) => {
self.inner.wake_producer();
Ok(item)
}
Err(PopError::Empty) => Err(TryRecvError::Empty),
Err(PopError::Closed) => Err(TryRecvError::Closed),
}
}
#[must_use = "futures do nothing unless awaited"]
pub fn receive(&self) -> RecvFuture<'_, T> {
RecvFuture { receiver: self }
}
#[must_use]
pub fn readiness(&self) -> QueueReadiness<T>
where
T: Send,
{
QueueReadiness::new(self.inner.queue.clone())
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.queue.is_empty()
}
#[must_use]
pub fn is_closed(&self) -> bool {
self.inner.queue.is_closed()
}
#[must_use]
pub fn len(&self) -> usize {
self.inner.queue.len()
}
pub fn close(&self) -> bool {
let closed = self.inner.queue.close();
self.inner.wake_producer();
closed
}
}
impl<T> Drop for PipeReceiver<T> {
fn drop(&mut self) {
self.inner.queue.close();
self.inner.wake_producer();
}
}
pub struct RecvFuture<'a, T> {
receiver: &'a PipeReceiver<T>,
}
impl<T> Unpin for RecvFuture<'_, T> {}
impl<T> Future for RecvFuture<'_, T> {
type Output = Option<T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.receiver.inner.queue.pop() {
Ok(item) => {
self.receiver.inner.wake_producer();
Poll::Ready(Some(item))
}
Err(PopError::Closed) => Poll::Ready(None),
Err(PopError::Empty) => {
*self.receiver.inner.consumer_waker.lock().unwrap() = Some(cx.waker().clone());
match self.receiver.inner.queue.pop() {
Ok(item) => {
self.receiver.inner.wake_producer();
Poll::Ready(Some(item))
}
Err(PopError::Closed) => Poll::Ready(None),
Err(PopError::Empty) => Poll::Pending,
}
}
}
}
}
pub enum TrySendError<T> {
Full(T),
Closed(T),
}
impl<T> TrySendError<T> {
pub fn into_inner(self) -> T {
match self {
TrySendError::Full(item) | TrySendError::Closed(item) => item,
}
}
#[must_use]
pub fn is_full(&self) -> bool {
matches!(self, TrySendError::Full(_))
}
}
impl<T> fmt::Debug for TrySendError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TrySendError::Full(_) => f.write_str("TrySendError::Full(..)"),
TrySendError::Closed(_) => f.write_str("TrySendError::Closed(..)"),
}
}
}
impl<T> fmt::Display for TrySendError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TrySendError::Full(_) => f.write_str("sending into a full pipe"),
TrySendError::Closed(_) => f.write_str("sending into a closed pipe"),
}
}
}
#[cfg(feature = "std")]
impl<T> std::error::Error for TrySendError<T> {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TryRecvError {
Empty,
Closed,
}
impl fmt::Display for TryRecvError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TryRecvError::Empty => f.write_str("receiving from an empty pipe"),
TryRecvError::Closed => f.write_str("receiving from a closed, drained pipe"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for TryRecvError {}
pub struct SendError<T>(pub T);
impl<T> SendError<T> {
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> fmt::Debug for SendError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("SendError(..)")
}
}
impl<T> fmt::Display for SendError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("sending into a closed pipe")
}
}
#[cfg(feature = "std")]
impl<T> std::error::Error for SendError<T> {}