use std::pin::Pin;
use std::task::{Context, Poll, Waker, ready};
use bytes::{Bytes, BytesMut};
use futures::stream::SelectAll;
use futures::{Stream, StreamExt};
use pin_project_lite::pin_project;
use tokio_util::codec::Encoder;
use crate::{Identify, Protocol};
pin_project! {
pub struct MuxedEncodedStream<T: Protocol>
where
T::Message: Identify
{
#[pin]
streams: SelectAll<Pin<Box<T::StreamHalf>>>,
encoder: T::Codec,
waker: Option<Waker>,
end_method: EndMethod
}
}
#[derive(Debug)]
pub enum EndMethod {
None,
Now,
Empty,
}
impl<T: Protocol> MuxedEncodedStream<T>
where
T::Message: Identify,
{
pub fn new(encoder: T::Codec) -> Self {
Self {
streams: SelectAll::new(),
encoder,
waker: None,
end_method: EndMethod::None,
}
}
pub fn add(&mut self, stream: T::StreamHalf) {
self.streams.push(Box::pin(stream));
self.wake();
}
pub fn len(&self) -> usize {
self.streams.len()
}
pub fn is_empty(&self) -> bool {
self.streams.is_empty()
}
pub fn clear(&mut self) {
self.streams.clear();
}
pub fn set_end_method(&mut self, end_method: EndMethod) {
self.end_method = end_method;
self.wake();
}
fn set_waker(&mut self, cx: &mut Context) {
match self.waker.as_mut() {
Some(w) => w.clone_from(cx.waker()),
None => self.waker = Some(cx.waker().clone()),
}
}
fn wake(&self) {
if let Some(w) = self.waker.as_ref() {
w.wake_by_ref()
}
}
}
impl<T: Protocol> MuxedEncodedStream<T>
where
T::Message: Identify,
T::StreamHalf: Identify,
{
pub fn remove(&mut self, id: &u64) -> bool {
let old_streams = std::mem::replace(&mut self.streams, SelectAll::new());
let mut removed = false;
for stream in old_streams.into_iter() {
if &stream.id() == id {
removed = true;
} else {
self.streams.push(stream);
}
}
removed
}
}
impl<T: Protocol> Stream for MuxedEncodedStream<T>
where
T::Message: Identify,
{
type Item = Bytes;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
self.set_waker(cx);
if let EndMethod::Now = self.end_method {
return Poll::Ready(None);
}
match ready!(self.streams.poll_next_unpin(cx)) {
Some(msg) => {
let mut buf = BytesMut::new();
match self.encoder.encode(msg, &mut buf) {
Ok(()) => Poll::Ready(Some(buf.freeze())),
Err(_) => Poll::Ready(None),
}
}
None => match self.end_method {
EndMethod::None => Poll::Pending,
EndMethod::Now => Poll::Ready(None),
EndMethod::Empty => Poll::Ready(None),
},
}
}
}