use core::fmt::{self, Debug};
use core::iter::FromIterator;
use core::pin::Pin;
use futures_core::ready;
use futures_core::stream::{FusedStream, Stream};
use futures_core::task::{Context, Poll};
use pin_project_lite::pin_project;
use super::assert_stream;
use crate::stream::{futures_unordered, FuturesUnordered, StreamExt, StreamFuture};
pin_project! {
#[must_use = "streams do nothing unless polled"]
pub struct SelectAll<St> {
#[pin]
inner: FuturesUnordered<StreamFuture<St>>,
}
}
impl<St: Debug> Debug for SelectAll<St> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SelectAll {{ ... }}")
}
}
impl<St: Stream + Unpin> SelectAll<St> {
pub fn new() -> Self {
Self { inner: FuturesUnordered::new() }
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn push(&mut self, stream: St) {
self.inner.push(stream.into_future());
}
pub fn iter(&self) -> Iter<'_, St> {
Iter(self.inner.iter())
}
pub fn iter_mut(&mut self) -> IterMut<'_, St> {
IterMut(self.inner.iter_mut())
}
pub fn clear(&mut self) {
self.inner.clear()
}
}
impl<St: Stream + Unpin> Default for SelectAll<St> {
fn default() -> Self {
Self::new()
}
}
impl<St: Stream + Unpin> Stream for SelectAll<St> {
type Item = St::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
loop {
match ready!(self.inner.poll_next_unpin(cx)) {
Some((Some(item), remaining)) => {
self.push(remaining);
return Poll::Ready(Some(item));
}
Some((None, _)) => {
}
None => return Poll::Ready(None),
}
}
}
}
impl<St: Stream + Unpin> FusedStream for SelectAll<St> {
fn is_terminated(&self) -> bool {
self.inner.is_terminated()
}
}
pub fn select_all<I>(streams: I) -> SelectAll<I::Item>
where
I: IntoIterator,
I::Item: Stream + Unpin,
{
let mut set = SelectAll::new();
for stream in streams {
set.push(stream);
}
assert_stream::<<I::Item as Stream>::Item, _>(set)
}
impl<St: Stream + Unpin> FromIterator<St> for SelectAll<St> {
fn from_iter<T: IntoIterator<Item = St>>(iter: T) -> Self {
select_all(iter)
}
}
impl<St: Stream + Unpin> Extend<St> for SelectAll<St> {
fn extend<T: IntoIterator<Item = St>>(&mut self, iter: T) {
for st in iter {
self.push(st)
}
}
}
impl<St: Stream + Unpin> IntoIterator for SelectAll<St> {
type Item = St;
type IntoIter = IntoIter<St>;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.inner.into_iter())
}
}
impl<'a, St: Stream + Unpin> IntoIterator for &'a SelectAll<St> {
type Item = &'a St;
type IntoIter = Iter<'a, St>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, St: Stream + Unpin> IntoIterator for &'a mut SelectAll<St> {
type Item = &'a mut St;
type IntoIter = IterMut<'a, St>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[derive(Debug)]
pub struct Iter<'a, St: Unpin>(futures_unordered::Iter<'a, StreamFuture<St>>);
#[derive(Debug)]
pub struct IterMut<'a, St: Unpin>(futures_unordered::IterMut<'a, StreamFuture<St>>);
#[derive(Debug)]
pub struct IntoIter<St: Unpin>(futures_unordered::IntoIter<StreamFuture<St>>);
impl<'a, St: Stream + Unpin> Iterator for Iter<'a, St> {
type Item = &'a St;
fn next(&mut self) -> Option<Self::Item> {
let st = self.0.next()?;
let next = st.get_ref();
debug_assert!(next.is_some());
next
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<St: Stream + Unpin> ExactSizeIterator for Iter<'_, St> {}
impl<'a, St: Stream + Unpin> Iterator for IterMut<'a, St> {
type Item = &'a mut St;
fn next(&mut self) -> Option<Self::Item> {
let st = self.0.next()?;
let next = st.get_mut();
debug_assert!(next.is_some());
next
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<St: Stream + Unpin> ExactSizeIterator for IterMut<'_, St> {}
impl<St: Stream + Unpin> Iterator for IntoIter<St> {
type Item = St;
fn next(&mut self) -> Option<Self::Item> {
let st = self.0.next()?;
let next = st.into_inner();
debug_assert!(next.is_some());
next
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<St: Stream + Unpin> ExactSizeIterator for IntoIter<St> {}