From 04a263c7001dc259a18fc5aac10d1f9a939a517c Mon Sep 17 00:00:00 2001 From: alexmoon Date: Mon, 4 Apr 2022 19:30:16 -0400 Subject: [PATCH 1/2] no_std version of `futures::future::select_all` --- embassy/src/util/mod.rs | 2 ++ embassy/src/util/select_all.rs | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 embassy/src/util/select_all.rs diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index 7744778b..f5cc9623 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs @@ -1,9 +1,11 @@ //! Misc utilities mod forever; +mod select_all; mod yield_now; pub use forever::*; +pub use select_all::*; pub use yield_now::*; /// Unsafely unborrow an owned singleton out of a `&mut`. diff --git a/embassy/src/util/select_all.rs b/embassy/src/util/select_all.rs new file mode 100644 index 00000000..1b9bddd6 --- /dev/null +++ b/embassy/src/util/select_all.rs @@ -0,0 +1,56 @@ +#![allow(dead_code)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +use futures::future::FutureExt; + +/// Future for the [`select_all`] function. +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct SelectAll { + inner: [Fut; N], +} + +impl Unpin for SelectAll {} + +/// Creates a new future which will select over a list of futures. +/// +/// The returned future will wait for any future within `iter` to be ready. Upon +/// completion the item resolved will be returned, along with the index of the +/// future that was ready. +/// +/// # Panics +/// +/// This function will panic if the array specified contains no items. +pub fn select_all(arr: [Fut; N]) -> Option> { + assert!(N > 0); + Some(SelectAll { inner: arr }) +} + +impl SelectAll { + /// Consumes this combinator, returning the underlying futures. + pub fn into_inner(self) -> [Fut; N] { + self.inner + } +} + +impl Future for SelectAll { + type Output = (Fut::Output, usize); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let item = self + .inner + .iter_mut() + .enumerate() + .find_map(|(i, f)| match f.poll_unpin(cx) { + Poll::Pending => None, + Poll::Ready(e) => Some((i, e)), + }); + match item { + Some((idx, res)) => Poll::Ready((res, idx)), + None => Poll::Pending, + } + } +} From e42295c4c51a35132595a7579de8467a38bc8171 Mon Sep 17 00:00:00 2001 From: alexmoon Date: Mon, 4 Apr 2022 21:24:10 -0400 Subject: [PATCH 2/2] Remove Unpin bound from SelectAll --- embassy/src/util/select_all.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/embassy/src/util/select_all.rs b/embassy/src/util/select_all.rs index 1b9bddd6..aef22d89 100644 --- a/embassy/src/util/select_all.rs +++ b/embassy/src/util/select_all.rs @@ -1,11 +1,7 @@ -#![allow(dead_code)] - use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll}; -use futures::future::FutureExt; - /// Future for the [`select_all`] function. #[derive(Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"] @@ -24,9 +20,9 @@ impl Unpin for SelectAll {} /// # Panics /// /// This function will panic if the array specified contains no items. -pub fn select_all(arr: [Fut; N]) -> Option> { +pub fn select_all(arr: [Fut; N]) -> SelectAll { assert!(N > 0); - Some(SelectAll { inner: arr }) + SelectAll { inner: arr } } impl SelectAll { @@ -36,18 +32,24 @@ impl SelectAll { } } -impl Future for SelectAll { +impl Future for SelectAll { type Output = (Fut::Output, usize); - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let item = self - .inner - .iter_mut() - .enumerate() - .find_map(|(i, f)| match f.poll_unpin(cx) { - Poll::Pending => None, - Poll::Ready(e) => Some((i, e)), - }); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move, + // its elements also cannot move. Therefore it is safe to access `inner` and pin + // references to the contained futures. + let item = unsafe { + self.get_unchecked_mut() + .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,