aboutsummaryrefslogtreecommitdiff
path: root/embassy-futures/src/select.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-futures/src/select.rs')
-rw-r--r--embassy-futures/src/select.rs230
1 files changed, 230 insertions, 0 deletions
diff --git a/embassy-futures/src/select.rs b/embassy-futures/src/select.rs
new file mode 100644
index 000000000..8cecb7fa0
--- /dev/null
+++ b/embassy-futures/src/select.rs
@@ -0,0 +1,230 @@
1use core::future::Future;
2use core::pin::Pin;
3use core::task::{Context, Poll};
4
5/// Result for [`select`].
6#[derive(Debug, Clone)]
7pub enum Either<A, B> {
8 /// First future finished first.
9 First(A),
10 /// Second future finished first.
11 Second(B),
12}
13
14/// Wait for one of two futures to complete.
15///
16/// This function returns a new future which polls all the futures.
17/// When one of them completes, it will complete with its result value.
18///
19/// The other future is dropped.
20pub fn select<A, B>(a: A, b: B) -> Select<A, B>
21where
22 A: Future,
23 B: Future,
24{
25 Select { a, b }
26}
27
28/// Future for the [`select`] function.
29#[derive(Debug)]
30#[must_use = "futures do nothing unless you `.await` or poll them"]
31pub struct Select<A, B> {
32 a: A,
33 b: B,
34}
35
36impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {}
37
38impl<A, B> Future for Select<A, B>
39where
40 A: Future,
41 B: Future,
42{
43 type Output = Either<A::Output, B::Output>;
44
45 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
46 let this = unsafe { self.get_unchecked_mut() };
47 let a = unsafe { Pin::new_unchecked(&mut this.a) };
48 let b = unsafe { Pin::new_unchecked(&mut this.b) };
49 if let Poll::Ready(x) = a.poll(cx) {
50 return Poll::Ready(Either::First(x));
51 }
52 if let Poll::Ready(x) = b.poll(cx) {
53 return Poll::Ready(Either::Second(x));
54 }
55 Poll::Pending
56 }
57}
58
59// ====================================================================
60
61/// Result for [`select3`].
62#[derive(Debug, Clone)]
63pub enum Either3<A, B, C> {
64 /// First future finished first.
65 First(A),
66 /// Second future finished first.
67 Second(B),
68 /// Third future finished first.
69 Third(C),
70}
71
72/// Same as [`select`], but with more futures.
73pub fn select3<A, B, C>(a: A, b: B, c: C) -> Select3<A, B, C>
74where
75 A: Future,
76 B: Future,
77 C: Future,
78{
79 Select3 { a, b, c }
80}
81
82/// Future for the [`select3`] function.
83#[derive(Debug)]
84#[must_use = "futures do nothing unless you `.await` or poll them"]
85pub struct Select3<A, B, C> {
86 a: A,
87 b: B,
88 c: C,
89}
90
91impl<A, B, C> Future for Select3<A, B, C>
92where
93 A: Future,
94 B: Future,
95 C: Future,
96{
97 type Output = Either3<A::Output, B::Output, C::Output>;
98
99 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
100 let this = unsafe { self.get_unchecked_mut() };
101 let a = unsafe { Pin::new_unchecked(&mut this.a) };
102 let b = unsafe { Pin::new_unchecked(&mut this.b) };
103 let c = unsafe { Pin::new_unchecked(&mut this.c) };
104 if let Poll::Ready(x) = a.poll(cx) {
105 return Poll::Ready(Either3::First(x));
106 }
107 if let Poll::Ready(x) = b.poll(cx) {
108 return Poll::Ready(Either3::Second(x));
109 }
110 if let Poll::Ready(x) = c.poll(cx) {
111 return Poll::Ready(Either3::Third(x));
112 }
113 Poll::Pending
114 }
115}
116
117// ====================================================================
118
119/// Result for [`select4`].
120#[derive(Debug, Clone)]
121pub enum Either4<A, B, C, D> {
122 /// First future finished first.
123 First(A),
124 /// Second future finished first.
125 Second(B),
126 /// Third future finished first.
127 Third(C),
128 /// Fourth future finished first.
129 Fourth(D),
130}
131
132/// Same as [`select`], but with more futures.
133pub fn select4<A, B, C, D>(a: A, b: B, c: C, d: D) -> Select4<A, B, C, D>
134where
135 A: Future,
136 B: Future,
137 C: Future,
138 D: Future,
139{
140 Select4 { a, b, c, d }
141}
142
143/// Future for the [`select4`] function.
144#[derive(Debug)]
145#[must_use = "futures do nothing unless you `.await` or poll them"]
146pub struct Select4<A, B, C, D> {
147 a: A,
148 b: B,
149 c: C,
150 d: D,
151}
152
153impl<A, B, C, D> Future for Select4<A, B, C, D>
154where
155 A: Future,
156 B: Future,
157 C: Future,
158 D: Future,
159{
160 type Output = Either4<A::Output, B::Output, C::Output, D::Output>;
161
162 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
163 let this = unsafe { self.get_unchecked_mut() };
164 let a = unsafe { Pin::new_unchecked(&mut this.a) };
165 let b = unsafe { Pin::new_unchecked(&mut this.b) };
166 let c = unsafe { Pin::new_unchecked(&mut this.c) };
167 let d = unsafe { Pin::new_unchecked(&mut this.d) };
168 if let Poll::Ready(x) = a.poll(cx) {
169 return Poll::Ready(Either4::First(x));
170 }
171 if let Poll::Ready(x) = b.poll(cx) {
172 return Poll::Ready(Either4::Second(x));
173 }
174 if let Poll::Ready(x) = c.poll(cx) {
175 return Poll::Ready(Either4::Third(x));
176 }
177 if let Poll::Ready(x) = d.poll(cx) {
178 return Poll::Ready(Either4::Fourth(x));
179 }
180 Poll::Pending
181 }
182}
183
184// ====================================================================
185
186/// Future for the [`select_all`] function.
187#[derive(Debug)]
188#[must_use = "futures do nothing unless you `.await` or poll them"]
189pub struct SelectAll<Fut, const N: usize> {
190 inner: [Fut; N],
191}
192
193/// Creates a new future which will select over a list of futures.
194///
195/// The returned future will wait for any future within `iter` to be ready. Upon
196/// completion the item resolved will be returned, along with the index of the
197/// future that was ready.
198///
199/// # Panics
200///
201/// This function will panic if the array specified contains no items.
202pub fn select_all<Fut: Future, const N: usize>(arr: [Fut; N]) -> SelectAll<Fut, N> {
203 assert!(N > 0);
204 SelectAll { inner: arr }
205}
206
207impl<Fut: Future, const N: usize> Future for SelectAll<Fut, N> {
208 type Output = (Fut::Output, usize);
209
210 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
211 // Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move,
212 // its elements also cannot move. Therefore it is safe to access `inner` and pin
213 // references to the contained futures.
214 let item = unsafe {
215 self.get_unchecked_mut()
216 .inner
217 .iter_mut()
218 .enumerate()
219 .find_map(|(i, f)| match Pin::new_unchecked(f).poll(cx) {
220 Poll::Pending => None,
221 Poll::Ready(e) => Some((i, e)),
222 })
223 };
224
225 match item {
226 Some((idx, res)) => Poll::Ready((res, idx)),
227 None => Poll::Pending,
228 }
229 }
230}