futures_concurrency/utils/futures/
array.rs

1use core::{
2    mem::{self, ManuallyDrop, MaybeUninit},
3    pin::Pin,
4};
5
6/// An array of futures which can be dropped in-place, intended to be
7/// constructed once and then accessed through pin projections.
8pub(crate) struct FutureArray<T, const N: usize> {
9    futures: [ManuallyDrop<T>; N],
10}
11
12impl<T, const N: usize> FutureArray<T, N> {
13    /// Create a new instance of `FutureArray`
14    pub(crate) fn new(futures: [T; N]) -> Self {
15        // Implementation copied from: https://doc.rust-lang.org/src/core/mem/maybe_uninit.rs.html#1292
16        let futures = MaybeUninit::new(futures);
17        // SAFETY: T and MaybeUninit<T> have the same layout
18        let futures = unsafe { mem::transmute_copy(&mem::ManuallyDrop::new(futures)) };
19        Self { futures }
20    }
21
22    /// Create an iterator of pinned references.
23    pub(crate) fn iter(self: Pin<&mut Self>) -> impl Iterator<Item = Pin<&mut ManuallyDrop<T>>> {
24        // SAFETY: `std` _could_ make this unsound if it were to decide Pin's
25        // invariants aren't required to transmit through slices. Otherwise this has
26        // the same safety as a normal field pin projection.
27        unsafe { self.get_unchecked_mut() }
28            .futures
29            .iter_mut()
30            .map(|t| unsafe { Pin::new_unchecked(t) })
31    }
32
33    /// Drop a future at the given index.
34    ///
35    /// # Safety
36    ///
37    /// The future is held in a `ManuallyDrop`, so no double-dropping, etc
38    pub(crate) unsafe fn drop(mut self: Pin<&mut Self>, idx: usize) {
39        unsafe {
40            let futures = self.as_mut().get_unchecked_mut().futures.as_mut();
41            ManuallyDrop::drop(&mut futures[idx]);
42        };
43    }
44}