use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use std::sync::Mutex;
use concurrent_queue::{PopError, PushError};
use crate::valtron::pipe::{PipeSender, PipeReceiver, SendError};
use crate::valtron::{QueueReadiness, QueueVacancyReadiness};
pub struct MappedSender<Inner, Outer, F> {
inner: PipeSender<Inner>,
f: F,
stashed: Mutex<Option<Inner>>,
_p: core::marker::PhantomData<Outer>,
}
impl<Inner, Outer, F> MappedSender<Inner, Outer, F>
where
F: Fn(&Outer) -> Inner,
{
pub fn try_send(&self, outer: &Outer) -> Result<(), ()> {
if let Some(inner) = self.stashed.lock().unwrap().take() {
self.inner.try_send(inner).map_err(|e| {
if e.is_full() {
*self.stashed.lock().unwrap() = Some(e.into_inner());
}
})?;
}
let inner = (self.f)(outer);
self.inner.try_send(inner).map_err(|e| {
if e.is_full() {
*self.stashed.lock().unwrap() = Some(e.into_inner());
}
})
}
pub fn send(&self, outer: Outer) -> MappedSendFuture<'_, Inner, Outer, F> {
MappedSendFuture {
sender: self,
outer: Some(outer),
stashed: None,
}
}
pub fn close(&self) -> bool { self.inner.close() }
pub fn is_full(&self) -> bool { self.inner.is_full() }
pub fn is_closed(&self) -> bool { self.inner.is_closed() }
pub fn len(&self) -> usize { self.inner.len() }
pub fn capacity(&self) -> usize { self.inner.capacity() }
pub fn vacancy(&self) -> QueueVacancyReadiness<Inner>
where Inner: Send { self.inner.vacancy() }
}
impl<Inner, Outer, F: Clone> Clone for MappedSender<Inner, Outer, F> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
f: self.f.clone(),
stashed: Mutex::new(None),
_p: core::marker::PhantomData,
}
}
}
impl<T> PipeSender<T> {
pub fn map_to<Outer, F: Fn(&Outer) -> T>(
self,
f: F,
) -> MappedSender<T, Outer, F> {
MappedSender {
inner: self,
f,
stashed: Mutex::new(None),
_p: core::marker::PhantomData,
}
}
}
pub struct MappedSendFuture<'a, Inner, Outer, F> {
sender: &'a MappedSender<Inner, Outer, F>,
outer: Option<Outer>,
stashed: Option<Inner>,
}
impl<Inner, Outer, F> Unpin for MappedSendFuture<'_, Inner, Outer, F> {}
impl<Inner, Outer, F> Future for MappedSendFuture<'_, Inner, Outer, F>
where
F: Fn(&Outer) -> Inner,
{
type Output = Result<(), SendError<Outer>>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let item: Inner = match self.stashed.take() {
Some(inner) => inner,
None => {
let outer = self.outer.as_ref().expect("polled after Ready");
(self.sender.f)(outer)
}
};
match self.sender.inner.inner.queue.push(item) {
Ok(()) => {
self.sender.inner.inner.wake_consumer();
Poll::Ready(Ok(()))
}
Err(PushError::Closed(_)) => {
Poll::Ready(Err(SendError(self.outer.take().expect("outer consumed"))))
}
Err(PushError::Full(item)) => {
*self.sender.inner.inner.producer_waker.lock().unwrap() = Some(cx.waker().clone());
match self.sender.inner.inner.queue.push(item) {
Ok(()) => {
self.sender.inner.inner.wake_consumer();
Poll::Ready(Ok(()))
}
Err(PushError::Closed(_)) => {
Poll::Ready(Err(SendError(self.outer.take().expect("outer consumed"))))
}
Err(PushError::Full(item)) => {
self.stashed = Some(item);
Poll::Pending
}
}
}
}
}
}
pub struct FilterMapReceiver<Inner, Outer, F> {
inner: PipeReceiver<Inner>,
f: F,
_p: core::marker::PhantomData<Outer>,
}
impl<Inner, Outer, F> FilterMapReceiver<Inner, Outer, F>
where
F: Fn(&Inner) -> Option<Outer>,
{
pub fn try_recv(&self) -> Result<Outer, crate::valtron::pipe::TryRecvError> {
let inner = self.inner.try_recv()?;
(self.f)(&inner).ok_or(crate::valtron::pipe::TryRecvError::Empty)
}
pub fn receive(&self) -> FilterMapRecvFuture<'_, Inner, Outer, F> {
FilterMapRecvFuture { receiver: self }
}
pub fn close(&self) -> bool { self.inner.close() }
pub fn is_empty(&self) -> bool { self.inner.is_empty() }
pub fn is_closed(&self) -> bool { self.inner.is_closed() }
pub fn len(&self) -> usize { self.inner.len() }
pub fn readiness(&self) -> QueueReadiness<Inner>
where Inner: Send { self.inner.readiness() }
}
impl<Inner, Outer, F: Clone> Clone for FilterMapReceiver<Inner, Outer, F> {
fn clone(&self) -> Self {
Self { inner: self.inner.clone(), f: self.f.clone(), _p: core::marker::PhantomData }
}
}
impl<T> PipeReceiver<T> {
pub fn filter_map_to<Outer, F>(
self,
f: F,
) -> FilterMapReceiver<T, Outer, F> {
FilterMapReceiver { inner: self, f, _p: core::marker::PhantomData }
}
}
pub struct FilterMapRecvFuture<'a, Inner, Outer, F> {
receiver: &'a FilterMapReceiver<Inner, Outer, F>,
}
impl<Inner, Outer, F> Unpin for FilterMapRecvFuture<'_, Inner, Outer, F> {}
impl<Inner, Outer, F> Future for FilterMapRecvFuture<'_, Inner, Outer, F>
where
F: Fn(&Inner) -> Option<Outer>,
{
type Output = Option<Outer>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.receiver.inner.inner.queue.pop() {
Ok(item) => {
self.receiver.inner.inner.wake_producer();
if let Some(outer) = (self.receiver.f)(&item) {
return Poll::Ready(Some(outer));
}
}
Err(PopError::Closed) => return Poll::Ready(None),
Err(PopError::Empty) => {}
}
*self.receiver.inner.inner.consumer_waker.lock().unwrap() = Some(cx.waker().clone());
match self.receiver.inner.inner.queue.pop() {
Ok(item) => {
self.receiver.inner.inner.wake_producer();
match (self.receiver.f)(&item) {
Some(outer) => Poll::Ready(Some(outer)),
None => Poll::Pending,
}
}
Err(PopError::Closed) => Poll::Ready(None),
Err(PopError::Empty) => Poll::Pending,
}
}
}