futures_util/stream/
select_all.rs

1//! An unbounded set of streams
2
3use std::fmt::{self, Debug};
4
5use futures_core::{Async, Poll, Stream};
6use futures_core::task;
7
8use stream::{StreamExt, StreamFuture, FuturesUnordered};
9
10/// An unbounded set of streams
11///
12/// This "combinator" provides the ability to maintain a set of streams
13/// and drive them all to completion.
14///
15/// Streams are pushed into this set and their realized values are
16/// yielded as they become ready. Streams will only be polled when they
17/// generate notifications. This allows to coordinate a large number of streams.
18///
19/// Note that you can create a ready-made `SelectAll` via the
20/// `select_all` function in the `stream` module, or you can start with an
21/// empty set with the `SelectAll::new` constructor.
22#[must_use = "streams do nothing unless polled"]
23pub struct SelectAll<S> {
24    inner: FuturesUnordered<StreamFuture<S>>,
25}
26
27impl<T: Debug> Debug for SelectAll<T> {
28    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
29        write!(fmt, "SelectAll {{ ... }}")
30    }
31}
32
33impl<S: Stream> SelectAll<S> {
34    /// Constructs a new, empty `SelectAll`
35    ///
36    /// The returned `SelectAll` does not contain any streams and, in this
37    /// state, `SelectAll::poll` will return `Ok(Async::Ready(None))`.
38    pub fn new() -> SelectAll<S> {
39        SelectAll { inner: FuturesUnordered::new() }
40    }
41
42    /// Returns the number of streams contained in the set.
43    ///
44    /// This represents the total number of in-flight streams.
45    pub fn len(&self) -> usize {
46        self.inner.len()
47    }
48
49    /// Returns `true` if the set contains no streams
50    pub fn is_empty(&self) -> bool {
51        self.inner.is_empty()
52    }
53
54    /// Push a stream into the set.
55    ///
56    /// This function submits the given stream to the set for managing. This
57    /// function will not call `poll` on the submitted stream. The caller must
58    /// ensure that `SelectAll::poll` is called in order to receive task
59    /// notifications.
60    pub fn push(&mut self, stream: S) {
61        self.inner.push(stream.next());
62    }
63}
64
65impl<S: Stream> Stream for SelectAll<S> {
66    type Item = S::Item;
67    type Error = S::Error;
68
69    fn poll_next(&mut self, cx: &mut task::Context) -> Poll<Option<Self::Item>, Self::Error> {
70        loop {
71            match self.inner.poll_next(cx).map_err(|(err, _)| err)? {
72                Async::Pending => return Ok(Async::Pending),
73                Async::Ready(Some((Some(item), remaining))) => {
74                    self.push(remaining);
75                    return Ok(Async::Ready(Some(item)));
76                }
77                Async::Ready(Some((None, _))) => {}
78                Async::Ready(None) => return Ok(Async::Ready(None)),
79            }
80        }
81    }
82}
83
84/// Convert a list of streams into a `Stream` of results from the streams.
85///
86/// This essentially takes a list of streams (e.g. a vector, an iterator, etc.)
87/// and bundles them together into a single stream.
88/// The stream will yield items as they become available on the underlying
89/// streams internally, in the order they become available.
90///
91/// Note that the returned set can also be used to dynamically push more
92/// futures into the set as they become available.
93pub fn select_all<I>(streams: I) -> SelectAll<I::Item>
94    where I: IntoIterator,
95          I::Item: Stream
96{
97    let mut set = SelectAll::new();
98
99    for stream in streams {
100        set.push(stream);
101    }
102
103    return set
104}