Skip to main content

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