futures_util/stream/
select_all.rs

1//! An unbounded set of streams
2
3use core::fmt::{self, Debug};
4use core::iter::FromIterator;
5use core::pin::Pin;
6
7use futures_core::ready;
8use futures_core::stream::{FusedStream, Stream};
9use futures_core::task::{Context, Poll};
10
11use pin_project_lite::pin_project;
12
13use super::assert_stream;
14use crate::stream::{futures_unordered, FuturesUnordered, StreamExt, StreamFuture};
15
16pin_project! {
17    /// An unbounded set of streams
18    ///
19    /// This "combinator" provides the ability to maintain a set of streams
20    /// and drive them all to completion.
21    ///
22    /// Streams are pushed into this set and their realized values are
23    /// yielded as they become ready. Streams will only be polled when they
24    /// generate notifications. This allows to coordinate a large number of streams.
25    ///
26    /// Note that you can create a ready-made `SelectAll` via the
27    /// `select_all` function in the `stream` module, or you can start with an
28    /// empty set with the `SelectAll::new` constructor.
29    #[must_use = "streams do nothing unless polled"]
30    pub struct SelectAll<St> {
31        #[pin]
32        inner: FuturesUnordered<StreamFuture<St>>,
33    }
34}
35
36impl<St: Debug> Debug for SelectAll<St> {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(f, "SelectAll {{ ... }}")
39    }
40}
41
42impl<St: Stream + Unpin> SelectAll<St> {
43    /// Constructs a new, empty `SelectAll`
44    ///
45    /// The returned `SelectAll` does not contain any streams and, in this
46    /// state, `SelectAll::poll` will return `Poll::Ready(None)`.
47    pub fn new() -> Self {
48        Self { inner: FuturesUnordered::new() }
49    }
50
51    /// Returns the number of streams contained in the set.
52    ///
53    /// This represents the total number of in-flight streams.
54    pub fn len(&self) -> usize {
55        self.inner.len()
56    }
57
58    /// Returns `true` if the set contains no streams
59    pub fn is_empty(&self) -> bool {
60        self.inner.is_empty()
61    }
62
63    /// Push a stream into the set.
64    ///
65    /// This function submits the given stream to the set for managing. This
66    /// function will not call `poll` on the submitted stream. The caller must
67    /// ensure that `SelectAll::poll` is called in order to receive task
68    /// notifications.
69    pub fn push(&mut self, stream: St) {
70        self.inner.push(stream.into_future());
71    }
72
73    /// Returns an iterator that allows inspecting each stream in the set.
74    pub fn iter(&self) -> Iter<'_, St> {
75        Iter(self.inner.iter())
76    }
77
78    /// Returns an iterator that allows modifying each stream in the set.
79    pub fn iter_mut(&mut self) -> IterMut<'_, St> {
80        IterMut(self.inner.iter_mut())
81    }
82
83    /// Clears the set, removing all streams.
84    pub fn clear(&mut self) {
85        self.inner.clear()
86    }
87}
88
89impl<St: Stream + Unpin> Default for SelectAll<St> {
90    fn default() -> Self {
91        Self::new()
92    }
93}
94
95impl<St: Stream + Unpin> Stream for SelectAll<St> {
96    type Item = St::Item;
97
98    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
99        loop {
100            match ready!(self.inner.poll_next_unpin(cx)) {
101                Some((Some(item), remaining)) => {
102                    self.push(remaining);
103                    return Poll::Ready(Some(item));
104                }
105                Some((None, _)) => {
106                    // `FuturesUnordered` thinks it isn't terminated
107                    // because it yielded a Some.
108                    // We do not return, but poll `FuturesUnordered`
109                    // in the next loop iteration.
110                }
111                None => return Poll::Ready(None),
112            }
113        }
114    }
115}
116
117impl<St: Stream + Unpin> FusedStream for SelectAll<St> {
118    fn is_terminated(&self) -> bool {
119        self.inner.is_terminated()
120    }
121}
122
123/// Convert a list of streams into a `Stream` of results from the streams.
124///
125/// This essentially takes a list of streams (e.g. a vector, an iterator, etc.)
126/// and bundles them together into a single stream.
127/// The stream will yield items as they become available on the underlying
128/// streams internally, in the order they become available.
129///
130/// Note that the returned set can also be used to dynamically push more
131/// streams into the set as they become available.
132///
133/// This function is only available when the `std` or `alloc` feature of this
134/// library is activated, and it is activated by default.
135pub fn select_all<I>(streams: I) -> SelectAll<I::Item>
136where
137    I: IntoIterator,
138    I::Item: Stream + Unpin,
139{
140    let mut set = SelectAll::new();
141
142    for stream in streams {
143        set.push(stream);
144    }
145
146    assert_stream::<<I::Item as Stream>::Item, _>(set)
147}
148
149impl<St: Stream + Unpin> FromIterator<St> for SelectAll<St> {
150    fn from_iter<T: IntoIterator<Item = St>>(iter: T) -> Self {
151        select_all(iter)
152    }
153}
154
155impl<St: Stream + Unpin> Extend<St> for SelectAll<St> {
156    fn extend<T: IntoIterator<Item = St>>(&mut self, iter: T) {
157        for st in iter {
158            self.push(st)
159        }
160    }
161}
162
163impl<St: Stream + Unpin> IntoIterator for SelectAll<St> {
164    type Item = St;
165    type IntoIter = IntoIter<St>;
166
167    fn into_iter(self) -> Self::IntoIter {
168        IntoIter(self.inner.into_iter())
169    }
170}
171
172impl<'a, St: Stream + Unpin> IntoIterator for &'a SelectAll<St> {
173    type Item = &'a St;
174    type IntoIter = Iter<'a, St>;
175
176    fn into_iter(self) -> Self::IntoIter {
177        self.iter()
178    }
179}
180
181impl<'a, St: Stream + Unpin> IntoIterator for &'a mut SelectAll<St> {
182    type Item = &'a mut St;
183    type IntoIter = IterMut<'a, St>;
184
185    fn into_iter(self) -> Self::IntoIter {
186        self.iter_mut()
187    }
188}
189
190/// Immutable iterator over all streams in the unordered set.
191#[derive(Debug)]
192pub struct Iter<'a, St: Unpin>(futures_unordered::Iter<'a, StreamFuture<St>>);
193
194/// Mutable iterator over all streams in the unordered set.
195#[derive(Debug)]
196pub struct IterMut<'a, St: Unpin>(futures_unordered::IterMut<'a, StreamFuture<St>>);
197
198/// Owned iterator over all streams in the unordered set.
199#[derive(Debug)]
200pub struct IntoIter<St: Unpin>(futures_unordered::IntoIter<StreamFuture<St>>);
201
202impl<'a, St: Stream + Unpin> Iterator for Iter<'a, St> {
203    type Item = &'a St;
204
205    fn next(&mut self) -> Option<Self::Item> {
206        let st = self.0.next()?;
207        let next = st.get_ref();
208        // This should always be true because FuturesUnordered removes completed futures.
209        debug_assert!(next.is_some());
210        next
211    }
212
213    fn size_hint(&self) -> (usize, Option<usize>) {
214        self.0.size_hint()
215    }
216}
217
218impl<St: Stream + Unpin> ExactSizeIterator for Iter<'_, St> {}
219
220impl<'a, St: Stream + Unpin> Iterator for IterMut<'a, St> {
221    type Item = &'a mut St;
222
223    fn next(&mut self) -> Option<Self::Item> {
224        let st = self.0.next()?;
225        let next = st.get_mut();
226        // This should always be true because FuturesUnordered removes completed futures.
227        debug_assert!(next.is_some());
228        next
229    }
230
231    fn size_hint(&self) -> (usize, Option<usize>) {
232        self.0.size_hint()
233    }
234}
235
236impl<St: Stream + Unpin> ExactSizeIterator for IterMut<'_, St> {}
237
238impl<St: Stream + Unpin> Iterator for IntoIter<St> {
239    type Item = St;
240
241    fn next(&mut self) -> Option<Self::Item> {
242        let st = self.0.next()?;
243        let next = st.into_inner();
244        // This should always be true because FuturesUnordered removes completed futures.
245        debug_assert!(next.is_some());
246        next
247    }
248
249    fn size_hint(&self) -> (usize, Option<usize>) {
250        self.0.size_hint()
251    }
252}
253
254impl<St: Stream + Unpin> ExactSizeIterator for IntoIter<St> {}