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}