aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-04-05 17:20:16 +0000
committerGitHub <[email protected]>2022-04-05 17:20:16 +0000
commitf5cf465417741ede43e25d30ae3e09d31398023e (patch)
treeac38811cdc04d9f340d2b22fe2a00418cf9bc958
parentb0de865e0b4bf5cb6782d61d668125850ceb8e3b (diff)
parente42295c4c51a35132595a7579de8467a38bc8171 (diff)
Merge #693
693: no_std version of `futures::future::select_all` r=Dirbaio a=alexmoon Here's a no-std compatible version of `select_all`. It's not quite as useful as the original because it requires an array of Unpin futures to be pre-constructed instead of taking an iterator (which could return `Pin<Box<_>>` in `std`). And, of course, you don't get a `Vec` of the unfinished futures returned at completion. Still, I think it's cleaner than a long cons of select calls. I'll leave it up to you whether this is sufficiently general purpose to include in Embassy or not. Co-authored-by: alexmoon <[email protected]>
-rw-r--r--embassy/src/util/mod.rs2
-rw-r--r--embassy/src/util/select_all.rs58
2 files changed, 60 insertions, 0 deletions
diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs
index 7744778bd..f5cc96238 100644
--- a/embassy/src/util/mod.rs
+++ b/embassy/src/util/mod.rs
@@ -1,9 +1,11 @@
1//! Misc utilities 1//! Misc utilities
2 2
3mod forever; 3mod forever;
4mod select_all;
4mod yield_now; 5mod yield_now;
5 6
6pub use forever::*; 7pub use forever::*;
8pub use select_all::*;
7pub use yield_now::*; 9pub use yield_now::*;
8 10
9/// Unsafely unborrow an owned singleton out of a `&mut`. 11/// 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 000000000..aef22d894
--- /dev/null
+++ b/embassy/src/util/select_all.rs
@@ -0,0 +1,58 @@
1use core::future::Future;
2use core::pin::Pin;
3use core::task::{Context, Poll};
4
5/// Future for the [`select_all`] function.
6#[derive(Debug)]
7#[must_use = "futures do nothing unless you `.await` or poll them"]
8pub struct SelectAll<Fut, const N: usize> {
9 inner: [Fut; N],
10}
11
12impl<Fut: Unpin, const N: usize> Unpin for SelectAll<Fut, N> {}
13
14/// Creates a new future which will select over a list of futures.
15///
16/// The returned future will wait for any future within `iter` to be ready. Upon
17/// completion the item resolved will be returned, along with the index of the
18/// future that was ready.
19///
20/// # Panics
21///
22/// This function will panic if the array specified contains no items.
23pub fn select_all<Fut: Future, const N: usize>(arr: [Fut; N]) -> SelectAll<Fut, N> {
24 assert!(N > 0);
25 SelectAll { inner: arr }
26}
27
28impl<Fut, const N: usize> SelectAll<Fut, N> {
29 /// Consumes this combinator, returning the underlying futures.
30 pub fn into_inner(self) -> [Fut; N] {
31 self.inner
32 }
33}
34
35impl<Fut: Future, const N: usize> Future for SelectAll<Fut, N> {
36 type Output = (Fut::Output, usize);
37
38 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
39 // Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move,
40 // its elements also cannot move. Therefore it is safe to access `inner` and pin
41 // references to the contained futures.
42 let item = unsafe {
43 self.get_unchecked_mut()
44 .inner
45 .iter_mut()
46 .enumerate()
47 .find_map(|(i, f)| match Pin::new_unchecked(f).poll(cx) {
48 Poll::Pending => None,
49 Poll::Ready(e) => Some((i, e)),
50 })
51 };
52
53 match item {
54 Some((idx, res)) => Poll::Ready((res, idx)),
55 None => Poll::Pending,
56 }
57 }
58}