Skip to main content

futures_concurrency/stream/
stream_group.rs

1use alloc::collections::BTreeSet;
2use core::fmt::{self, Debug};
3use core::ops::{Deref, DerefMut};
4use core::pin::Pin;
5use core::task::{Context, Poll};
6use futures_core::Stream;
7use smallvec::{smallvec, SmallVec};
8
9use crate::utils::{ChunkedVec, PollState, PollVec, WakerVec};
10
11/// A growable group of streams which act as a single unit.
12///
13/// # Example
14///
15/// **Basic example**
16///
17/// ```rust
18/// use futures_concurrency::stream::StreamGroup;
19/// use futures_lite::{stream, StreamExt};
20///
21/// # futures_lite::future::block_on(async {
22/// let mut group = StreamGroup::new();
23/// group.insert(stream::once(2));
24/// group.insert(stream::once(4));
25///
26/// let mut out = 0;
27/// while let Some(num) = group.next().await {
28///     out += num;
29/// }
30/// assert_eq!(out, 6);
31/// # });
32/// ```
33///
34/// **Update the group on every iteration**
35///
36/// ```rust
37/// use futures_concurrency::stream::StreamGroup;
38/// use lending_stream::prelude::*;
39/// use futures_lite::stream;
40///
41/// # futures_lite::future::block_on(async {
42/// let mut group = StreamGroup::new();
43/// group.insert(stream::once(4));
44///
45/// let mut index = 3;
46/// let mut out = 0;
47/// let mut group = group.lend_mut();
48/// while let Some((group, num)) = group.next().await {
49///     if index != 0 {
50///         group.insert(stream::once(index));
51///         index -= 1;
52///     }
53///     out += num;
54/// }
55/// assert_eq!(out, 10);
56/// # });
57/// ```
58#[must_use = "`StreamGroup` does nothing if not iterated over"]
59#[derive(Default)]
60#[pin_project::pin_project]
61pub struct StreamGroup<S> {
62    #[pin]
63    streams: ChunkedVec<S>,
64    wakers: WakerVec,
65    states: PollVec,
66    keys: BTreeSet<usize>,
67    key_removal_queue: SmallVec<[usize; 10]>,
68}
69
70impl<T: Debug> Debug for StreamGroup<T> {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        f.debug_struct("StreamGroup")
73            .field("streams", &"[..]")
74            .field("len", &self.len())
75            .field("capacity", &self.capacity())
76            .finish()
77    }
78}
79
80impl<S> StreamGroup<S> {
81    /// Create a new instance of `StreamGroup`.
82    ///
83    /// # Example
84    ///
85    /// ```rust
86    /// use futures_concurrency::stream::StreamGroup;
87    ///
88    /// let group = StreamGroup::new();
89    /// # let group: StreamGroup<usize> = group;
90    /// ```
91    pub fn new() -> Self {
92        Self::with_capacity(0)
93    }
94
95    /// Create a new instance of `StreamGroup` with a given capacity.
96    ///
97    /// # Example
98    ///
99    /// ```rust
100    /// use futures_concurrency::stream::StreamGroup;
101    ///
102    /// let group = StreamGroup::with_capacity(2);
103    /// # let group: StreamGroup<usize> = group;
104    /// ```
105    pub fn with_capacity(capacity: usize) -> Self {
106        Self {
107            streams: ChunkedVec::with_capacity(capacity),
108            wakers: WakerVec::new(capacity),
109            states: PollVec::new(capacity),
110            keys: BTreeSet::new(),
111            key_removal_queue: smallvec![],
112        }
113    }
114
115    /// Return the number of futures currently active in the group.
116    ///
117    /// # Example
118    ///
119    /// ```rust
120    /// use futures_concurrency::stream::StreamGroup;
121    /// use futures_lite::stream;
122    ///
123    /// let mut group = StreamGroup::with_capacity(2);
124    /// assert_eq!(group.len(), 0);
125    /// group.insert(stream::once(12));
126    /// assert_eq!(group.len(), 1);
127    /// ```
128    #[inline(always)]
129    pub fn len(&self) -> usize {
130        self.streams.len()
131    }
132
133    /// Return the capacity of the `StreamGroup`.
134    ///
135    /// # Example
136    ///
137    /// ```rust
138    /// use futures_concurrency::stream::StreamGroup;
139    /// use futures_lite::stream;
140    ///
141    /// let group = StreamGroup::with_capacity(2);
142    /// assert!(group.capacity() >= 2);
143    /// # let group: StreamGroup<usize> = group;
144    /// ```
145    pub fn capacity(&self) -> usize {
146        self.streams.capacity()
147    }
148
149    /// Returns true if there are no futures currently active in the group.
150    ///
151    /// # Example
152    ///
153    /// ```rust
154    /// use futures_concurrency::stream::StreamGroup;
155    /// use futures_lite::stream;
156    ///
157    /// let mut group = StreamGroup::with_capacity(2);
158    /// assert!(group.is_empty());
159    /// group.insert(stream::once(12));
160    /// assert!(!group.is_empty());
161    /// ```
162    #[inline(always)]
163    pub fn is_empty(&self) -> bool {
164        self.streams.is_empty()
165    }
166
167    /// Removes a stream from the group. Returns whether the value was present in
168    /// the group.
169    ///
170    /// # Example
171    ///
172    /// ```
173    /// use futures_lite::stream;
174    /// use futures_concurrency::stream::StreamGroup;
175    ///
176    /// # futures_lite::future::block_on(async {
177    /// let mut group = StreamGroup::new();
178    /// let key = group.insert(stream::once(4));
179    /// assert_eq!(group.len(), 1);
180    /// group.remove(key);
181    /// assert_eq!(group.len(), 0);
182    /// # })
183    /// ```
184    pub fn remove(&mut self, key: Key) -> bool {
185        let is_present = self.keys.remove(&key.0);
186        if is_present {
187            self.states[key.0].set_none();
188            self.streams.remove(key.0);
189        }
190        is_present
191    }
192
193    /// Returns `true` if the `StreamGroup` contains a value for the specified key.
194    ///
195    /// # Example
196    ///
197    /// ```
198    /// use futures_lite::stream;
199    /// use futures_concurrency::stream::StreamGroup;
200    ///
201    /// # futures_lite::future::block_on(async {
202    /// let mut group = StreamGroup::new();
203    /// let key = group.insert(stream::once(4));
204    /// assert!(group.contains_key(key));
205    /// group.remove(key);
206    /// assert!(!group.contains_key(key));
207    /// # })
208    /// ```
209    pub fn contains_key(&mut self, key: Key) -> bool {
210        self.keys.contains(&key.0)
211    }
212
213    /// Reserves capacity for `additional` more streams to be inserted.
214    /// Does nothing if the capacity is already sufficient.
215    ///
216    /// # Example
217    ///
218    /// ```rust
219    /// use futures_concurrency::stream::StreamGroup;
220    /// use futures_lite::stream::Once;
221    /// # futures_lite::future::block_on(async {
222    /// let mut group: StreamGroup<Once<usize>> = StreamGroup::with_capacity(0);
223    /// assert_eq!(group.capacity(), 0);
224    /// group.reserve(10);
225    /// assert!(group.capacity() >= 10);
226    ///
227    /// // does nothing if capacity is sufficient
228    /// group.reserve(5);
229    /// assert!(group.capacity() >= 10);
230    /// # })
231    /// ```
232    pub fn reserve(&mut self, additional: usize) {
233        self.streams.reserve(additional);
234        let new_cap = self.streams.capacity();
235        self.wakers.resize(new_cap);
236        self.states.resize(new_cap);
237    }
238}
239
240impl<S: Stream> StreamGroup<S> {
241    /// Insert a new stream into the group.
242    ///
243    /// # Example
244    ///
245    /// ```rust
246    /// use futures_concurrency::stream::StreamGroup;
247    /// use futures_lite::stream;
248    ///
249    /// let mut group = StreamGroup::with_capacity(2);
250    /// group.insert(stream::once(12));
251    /// ```
252    pub fn insert(&mut self, stream: S) -> Key
253    where
254        S: Stream,
255    {
256        let index = self.streams.insert(stream);
257        self.keys.insert(index);
258
259        // Ensure wakers and states have enough capacity
260        let new_cap = self.streams.capacity();
261        self.wakers.resize(new_cap);
262        self.states.resize(new_cap);
263
264        // Set the corresponding state
265        self.states[index].set_pending();
266        self.wakers.readiness().set_ready(index);
267
268        Key(index)
269    }
270
271    /// Create a stream which also yields the key of each item.
272    ///
273    /// # Example
274    ///
275    /// ```rust
276    /// use futures_concurrency::stream::StreamGroup;
277    /// use futures_lite::{stream, StreamExt};
278    ///
279    /// # futures_lite::future::block_on(async {
280    /// let mut group = StreamGroup::new();
281    /// group.insert(stream::once(2));
282    /// group.insert(stream::once(4));
283    ///
284    /// let mut out = 0;
285    /// let mut group = group.keyed();
286    /// while let Some((_key, num)) = group.next().await {
287    ///     out += num;
288    /// }
289    /// assert_eq!(out, 6);
290    /// # });
291    /// ```
292    pub fn keyed(self) -> Keyed<S> {
293        Keyed { group: self }
294    }
295}
296
297impl<S: Stream> StreamGroup<S> {
298    fn poll_next_inner(
299        mut self: Pin<&mut Self>,
300        cx: &Context<'_>,
301    ) -> Poll<Option<(Key, <S as Stream>::Item)>> {
302        let mut this = self.as_mut().project();
303
304        // Short-circuit if we have no streams to iterate over
305        if this.streams.is_empty() {
306            return Poll::Ready(None);
307        }
308
309        // Set the top-level waker and check readiness
310        let mut readiness = this.wakers.readiness();
311        readiness.set_waker(cx.waker());
312        if !readiness.any_ready() {
313            // Nothing is ready yet
314            return Poll::Pending;
315        }
316
317        // Setup our stream state
318        let mut ret = Poll::Pending;
319        let mut done_count = 0;
320        let stream_count = this.streams.len();
321        let states = this.states;
322
323        // SAFETY: We unpin the stream set so we can later individually access
324        // single streams. Either to read from them or to drop them.
325        let streams = unsafe { this.streams.as_mut().get_unchecked_mut() };
326
327        for index in this.keys.iter().cloned() {
328            if states[index].is_pending() && readiness.clear_ready(index) {
329                // unlock readiness so we don't deadlock when polling
330                #[allow(clippy::drop_non_drop)]
331                drop(readiness);
332
333                // Obtain the intermediate waker.
334                let mut cx = Context::from_waker(this.wakers.get(index).unwrap());
335
336                // SAFETY: this stream here is a projection from the streams
337                // vec, which we're reading from.
338                let stream = unsafe { Pin::new_unchecked(&mut streams[index]) };
339                match stream.poll_next(&mut cx) {
340                    Poll::Ready(Some(item)) => {
341                        // Set the return type for the function
342                        ret = Poll::Ready(Some((Key(index), item)));
343
344                        // We just obtained an item from this index, make sure
345                        // we check it again on a next iteration
346                        states[index] = PollState::Pending;
347                        let mut readiness = this.wakers.readiness();
348                        readiness.set_ready(index);
349
350                        break;
351                    }
352                    Poll::Ready(None) => {
353                        // A stream has ended, make note of that
354                        done_count += 1;
355
356                        // Remove all associated data about the stream.
357                        // The only data we can't remove directly is the key entry.
358                        states[index] = PollState::None;
359                        streams.remove(index);
360                        this.key_removal_queue.push(index);
361                    }
362                    // Keep looping if there is nothing for us to do
363                    Poll::Pending => {}
364                };
365
366                // Lock readiness so we can use it again
367                readiness = this.wakers.readiness();
368            }
369        }
370
371        // Now that we're no longer borrowing `this.keys` we can loop over
372        // which items we need to remove
373        if !this.key_removal_queue.is_empty() {
374            for key in this.key_removal_queue.iter() {
375                this.keys.remove(key);
376            }
377            this.key_removal_queue.clear();
378        }
379
380        // If all streams turned up with `Poll::Ready(None)` our
381        // stream should return that
382        if done_count == stream_count {
383            ret = Poll::Ready(None);
384        }
385
386        ret
387    }
388}
389
390impl<S: Stream> Stream for StreamGroup<S> {
391    type Item = <S as Stream>::Item;
392
393    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
394        match self.poll_next_inner(cx) {
395            Poll::Ready(Some((_key, item))) => Poll::Ready(Some(item)),
396            Poll::Ready(None) => Poll::Ready(None),
397            Poll::Pending => Poll::Pending,
398        }
399    }
400}
401
402impl<S: Stream> FromIterator<S> for StreamGroup<S> {
403    fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Self {
404        let iter = iter.into_iter();
405        let len = iter.size_hint().1.unwrap_or_default();
406        let mut this = Self::with_capacity(len);
407        for stream in iter {
408            this.insert(stream);
409        }
410        this
411    }
412}
413
414/// A key used to index into the `StreamGroup` type.
415#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
416pub struct Key(usize);
417
418/// Iterate over items in the stream group with their associated keys.
419#[derive(Debug)]
420#[pin_project::pin_project]
421pub struct Keyed<S: Stream> {
422    #[pin]
423    group: StreamGroup<S>,
424}
425
426impl<S: Stream> Deref for Keyed<S> {
427    type Target = StreamGroup<S>;
428
429    fn deref(&self) -> &Self::Target {
430        &self.group
431    }
432}
433
434impl<S: Stream> DerefMut for Keyed<S> {
435    fn deref_mut(&mut self) -> &mut Self::Target {
436        &mut self.group
437    }
438}
439
440impl<S: Stream> Stream for Keyed<S> {
441    type Item = (Key, <S as Stream>::Item);
442
443    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
444        let mut this = self.project();
445        this.group.as_mut().poll_next_inner(cx)
446    }
447}
448
449#[cfg(test)]
450mod test {
451    use super::StreamGroup;
452    use futures_lite::{prelude::*, stream};
453
454    #[test]
455    fn smoke() {
456        futures_lite::future::block_on(async {
457            let mut group = StreamGroup::new();
458            group.insert(stream::once(2));
459            group.insert(stream::once(4));
460
461            let mut out = 0;
462            while let Some(num) = group.next().await {
463                out += num;
464            }
465            assert_eq!(out, 6);
466            assert_eq!(group.len(), 0);
467            assert!(group.is_empty());
468        });
469    }
470
471    #[test]
472    fn capacity_grow_on_insert() {
473        futures_lite::future::block_on(async {
474            let mut group = StreamGroup::new();
475            let cap = group.capacity();
476
477            group.insert(stream::once(1));
478
479            assert!(group.capacity() > cap);
480        });
481    }
482}