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}