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}