use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, ready};
use bytes::Bytes;
use futures::{Stream, StreamExt};
use pin_project_lite::pin_project;
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::sync::watch;
use tokio_stream::wrappers::WatchStream;
use tokio_util::sync::CancellationToken;
use crate::sync::PollMutex;
pin_project! {
pub struct SharedStream<T: Stream> {
#[pin]
stream: PollMutex<Pin<Box<T>>>,
}
}
impl<T: Stream> SharedStream<T> {
pub fn new(stream: T) -> Self {
Self {
stream: PollMutex::new(Box::pin(stream)),
}
}
}
impl<T: Stream> Stream for SharedStream<T> {
type Item = T::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let mut locked_stream = ready!(self.project().stream.poll_lock(cx));
locked_stream.poll_next_unpin(cx)
}
}
impl<T: Stream> Clone for SharedStream<T> {
fn clone(&self) -> Self {
Self {
stream: self.stream.clone(),
}
}
}
impl<T: Stream> Deref for SharedStream<T> {
type Target = PollMutex<Pin<Box<T>>>;
fn deref(&self) -> &Self::Target {
&self.stream
}
}
impl<T: Stream> DerefMut for SharedStream<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.stream
}
}
pin_project! {
pub struct SharedReplaceableStream<T: Stream> {
stream: PollMutex<Option<Pin<Box<T>>>>,
}
}
impl<T: Stream> SharedReplaceableStream<T> {
pub fn new(stream: T) -> Self {
Self {
stream: PollMutex::new(Some(Box::pin(stream))),
}
}
pub async fn take_inner(&mut self) -> Option<Pin<Box<T>>> {
self.stream.lock().await.take()
}
pub async fn replace_inner(&mut self, value: Pin<Box<T>>) -> Option<Pin<Box<T>>> {
self.stream.lock().await.replace(value)
}
}
impl<T: Stream> Stream for SharedReplaceableStream<T> {
type Item = T::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let mut locked_option = ready!(self.project().stream.poll_lock(cx));
match locked_option.as_mut() {
Some(stream) => stream.poll_next_unpin(cx),
None => Poll::Ready(None),
}
}
}
impl<T: Stream> Clone for SharedReplaceableStream<T> {
fn clone(&self) -> Self {
Self {
stream: self.stream.clone(),
}
}
}
pin_project! {
pub struct ChannelStream<T, U> {
channel: UnboundedReceiver<T>,
#[pin]
next: U,
next_toggle: Option<WatchStream<bool>>,
next_closed: Option<CancellationToken>,
is_eof_channel: bool,
is_eof_next: bool,
poll_next: bool,
}
}
impl<T, U> ChannelStream<T, U> {
pub fn new(
channel: UnboundedReceiver<T>,
next: U,
next_toggle: Option<watch::Receiver<bool>>,
next_closed: Option<CancellationToken>,
) -> Self {
let next_toggle = next_toggle.map(WatchStream::new);
Self {
channel,
next,
next_toggle,
next_closed,
is_eof_channel: false,
is_eof_next: false,
poll_next: true, }
}
}
impl<T, U> Stream for ChannelStream<T, U>
where
T: From<Bytes>,
U: Stream<Item = Bytes>,
{
type Item = T;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let mut this = self.project();
if !*this.is_eof_channel {
match this.channel.poll_recv(cx) {
Poll::Ready(Some(item)) => return Poll::Ready(Some(item)),
Poll::Ready(None) => *this.is_eof_channel = true,
Poll::Pending => {}
}
}
if !*this.is_eof_next {
while let Some(watch_rx) = this.next_toggle {
match watch_rx.poll_next_unpin(cx) {
Poll::Ready(Some(val)) => *this.poll_next = val,
Poll::Ready(None) => *this.next_toggle = None,
Poll::Pending => break, }
}
if *this.poll_next || this.next_toggle.is_none() {
match this.next.poll_next_unpin(cx).map(|o| o.map(|b| T::from(b))) {
Poll::Ready(Some(item)) => return Poll::Ready(Some(item)),
Poll::Ready(None) => {
*this.is_eof_next = true;
if let Some(token) = this.next_closed {
token.cancel();
}
}
Poll::Pending => {}
}
}
}
if *this.is_eof_channel && *this.is_eof_next {
Poll::Ready(None)
} else {
Poll::Pending
}
}
}