mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
fix: select_slice
is unsound. fixes #3320
This commit is contained in:
parent
dc98d865ff
commit
29932c295c
@ -237,7 +237,7 @@ impl<Fut: Future, const N: usize> Future for SelectArray<Fut, N> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct SelectSlice<'a, Fut> {
|
pub struct SelectSlice<'a, Fut> {
|
||||||
inner: &'a mut [Fut],
|
inner: Pin<&'a mut [Fut]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new future which will select over a slice of futures.
|
/// Creates a new future which will select over a slice of futures.
|
||||||
@ -247,31 +247,26 @@ pub struct SelectSlice<'a, Fut> {
|
|||||||
/// future that was ready.
|
/// future that was ready.
|
||||||
///
|
///
|
||||||
/// If the slice is empty, the resulting future will be Pending forever.
|
/// If the slice is empty, the resulting future will be Pending forever.
|
||||||
pub fn select_slice<'a, Fut: Future>(slice: &'a mut [Fut]) -> SelectSlice<'a, Fut> {
|
pub fn select_slice<'a, Fut: Future>(slice: Pin<&'a mut [Fut]>) -> SelectSlice<'a, Fut> {
|
||||||
SelectSlice { inner: slice }
|
SelectSlice { inner: slice }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> {
|
impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> {
|
||||||
type Output = (Fut::Output, usize);
|
type Output = (Fut::Output, usize);
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
// Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move,
|
// Safety: refer to
|
||||||
// its elements also cannot move. Therefore it is safe to access `inner` and pin
|
// https://users.rust-lang.org/t/working-with-pinned-slices-are-there-any-structurally-pinning-vec-like-collection-types/50634/2
|
||||||
// references to the contained futures.
|
#[inline(always)]
|
||||||
let item = unsafe {
|
fn pin_iter<T>(slice: Pin<&mut [T]>) -> impl Iterator<Item = Pin<&mut T>> {
|
||||||
self.get_unchecked_mut()
|
unsafe { slice.get_unchecked_mut().iter_mut().map(|v| Pin::new_unchecked(v)) }
|
||||||
.inner
|
|
||||||
.iter_mut()
|
|
||||||
.enumerate()
|
|
||||||
.find_map(|(i, f)| match Pin::new_unchecked(f).poll(cx) {
|
|
||||||
Poll::Pending => None,
|
|
||||||
Poll::Ready(e) => Some((i, e)),
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
match item {
|
|
||||||
Some((idx, res)) => Poll::Ready((res, idx)),
|
|
||||||
None => Poll::Pending,
|
|
||||||
}
|
}
|
||||||
|
for (i, fut) in pin_iter(self.inner.as_mut()).enumerate() {
|
||||||
|
if let Poll::Ready(res) = fut.poll(cx) {
|
||||||
|
return Poll::Ready((res, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user