aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-04-12 21:27:13 +0000
committerGitHub <[email protected]>2022-04-12 21:27:13 +0000
commit5d48153bd752af283ced3621aa7e75ed6a67a0a2 (patch)
treefd606706f6018d7bb3f40478658246d41dfc2edc
parent77c2b151c239c470acd6b29a1d5ee8dfe64276b8 (diff)
parentf32fa1d33ae04274e831b30028f5e2747fbb0d05 (diff)
Merge #694
694: Add select, select3, select4. r=Dirbaio a=Dirbaio The difference with those from the `futures` crate is they don't return the other partially-run futures, so they can work with `!Unpin` futures which makes them much easier to use. Co-authored-by: Dario Nieuwenhuis <[email protected]>
-rw-r--r--embassy/src/util/mod.rs73
-rw-r--r--embassy/src/util/select.rs218
-rw-r--r--embassy/src/util/select_all.rs58
-rw-r--r--embassy/src/util/steal.rs3
-rw-r--r--embassy/src/util/unborrow.rs60
5 files changed, 287 insertions, 125 deletions
diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs
index f5cc96238..928edf0e2 100644
--- a/embassy/src/util/mod.rs
+++ b/embassy/src/util/mod.rs
@@ -1,74 +1,13 @@
1//! Misc utilities 1//! Misc utilities
2 2
3mod forever; 3mod forever;
4mod select_all; 4mod select;
5mod steal;
6mod unborrow;
5mod yield_now; 7mod yield_now;
6 8
7pub use forever::*; 9pub use forever::*;
8pub use select_all::*; 10pub use select::*;
11pub use steal::*;
12pub use unborrow::*;
9pub use yield_now::*; 13pub use yield_now::*;
10
11/// Unsafely unborrow an owned singleton out of a `&mut`.
12///
13/// It is intended to be implemented for owned peripheral singletons, such as `USART3` or `AnyPin`.
14/// Unborrowing an owned `T` yields the same `T`. Unborrowing a `&mut T` yields a copy of the T.
15///
16/// This allows writing HAL drivers that either own or borrow their peripherals, but that don't have
17/// to store pointers in the borrowed case.
18///
19/// Safety: this trait can be used to copy non-Copy types. Implementors must not cause
20/// immediate UB when copied, and must not cause UB when copies are later used, provided they
21/// are only used according the [`Self::unborrow`] safety contract.
22///
23pub unsafe trait Unborrow {
24 /// Unborrow result type
25 type Target;
26
27 /// Unborrow a value.
28 ///
29 /// Safety: This returns a copy of a singleton that's normally not
30 /// copiable. The returned copy must ONLY be used while the lifetime of `self` is
31 /// valid, as if it were accessed through `self` every time.
32 unsafe fn unborrow(self) -> Self::Target;
33}
34
35unsafe impl<'a, T: Unborrow> Unborrow for &'a mut T {
36 type Target = T::Target;
37 unsafe fn unborrow(self) -> Self::Target {
38 T::unborrow(core::ptr::read(self))
39 }
40}
41
42pub trait Steal {
43 unsafe fn steal() -> Self;
44}
45
46macro_rules! unsafe_impl_unborrow_tuples {
47 ($($t:ident),+) => {
48 unsafe impl<$($t),+> Unborrow for ($($t),+)
49 where
50 $(
51 $t: Unborrow<Target = $t>
52 ),+
53 {
54 type Target = ($($t),+);
55 unsafe fn unborrow(self) -> Self::Target {
56 self
57 }
58 }
59
60
61 };
62}
63
64unsafe_impl_unborrow_tuples!(A, B);
65unsafe_impl_unborrow_tuples!(A, B, C);
66unsafe_impl_unborrow_tuples!(A, B, C, D);
67unsafe_impl_unborrow_tuples!(A, B, C, D, E);
68unsafe_impl_unborrow_tuples!(A, B, C, D, E, F);
69unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G);
70unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H);
71unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I);
72unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J);
73unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J, K);
74unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J, K, L);
diff --git a/embassy/src/util/select.rs b/embassy/src/util/select.rs
new file mode 100644
index 000000000..ccc50f117
--- /dev/null
+++ b/embassy/src/util/select.rs
@@ -0,0 +1,218 @@
1use core::future::Future;
2use core::pin::Pin;
3use core::task::{Context, Poll};
4
5#[derive(Debug, Clone)]
6pub enum Either<A, B> {
7 First(A),
8 Second(B),
9}
10
11/// Wait for one of two futures to complete.
12///
13/// This function returns a new future which polls all the futures.
14/// When one of them completes, it will complete with its result value.
15///
16/// The other future is dropped.
17pub fn select<A, B>(a: A, b: B) -> Select<A, B>
18where
19 A: Future,
20 B: Future,
21{
22 Select { a, b }
23}
24
25/// Future for the [`select`] function.
26#[derive(Debug)]
27#[must_use = "futures do nothing unless you `.await` or poll them"]
28pub struct Select<A, B> {
29 a: A,
30 b: B,
31}
32
33impl<A: Unpin, B: Unpin> Unpin for Select<A, B> {}
34
35impl<A, B> Future for Select<A, B>
36where
37 A: Future,
38 B: Future,
39{
40 type Output = Either<A::Output, B::Output>;
41
42 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
43 let this = unsafe { self.get_unchecked_mut() };
44 let a = unsafe { Pin::new_unchecked(&mut this.a) };
45 let b = unsafe { Pin::new_unchecked(&mut this.b) };
46 if let Poll::Ready(x) = a.poll(cx) {
47 return Poll::Ready(Either::First(x));
48 }
49 if let Poll::Ready(x) = b.poll(cx) {
50 return Poll::Ready(Either::Second(x));
51 }
52 Poll::Pending
53 }
54}
55
56// ====================================================================
57
58#[derive(Debug, Clone)]
59pub enum Either3<A, B, C> {
60 First(A),
61 Second(B),
62 Third(C),
63}
64
65/// Same as [`select`], but with more futures.
66pub fn select3<A, B, C>(a: A, b: B, c: C) -> Select3<A, B, C>
67where
68 A: Future,
69 B: Future,
70 C: Future,
71{
72 Select3 { a, b, c }
73}
74
75/// Future for the [`select3`] function.
76#[derive(Debug)]
77#[must_use = "futures do nothing unless you `.await` or poll them"]
78pub struct Select3<A, B, C> {
79 a: A,
80 b: B,
81 c: C,
82}
83
84impl<A, B, C> Future for Select3<A, B, C>
85where
86 A: Future,
87 B: Future,
88 C: Future,
89{
90 type Output = Either3<A::Output, B::Output, C::Output>;
91
92 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
93 let this = unsafe { self.get_unchecked_mut() };
94 let a = unsafe { Pin::new_unchecked(&mut this.a) };
95 let b = unsafe { Pin::new_unchecked(&mut this.b) };
96 let c = unsafe { Pin::new_unchecked(&mut this.c) };
97 if let Poll::Ready(x) = a.poll(cx) {
98 return Poll::Ready(Either3::First(x));
99 }
100 if let Poll::Ready(x) = b.poll(cx) {
101 return Poll::Ready(Either3::Second(x));
102 }
103 if let Poll::Ready(x) = c.poll(cx) {
104 return Poll::Ready(Either3::Third(x));
105 }
106 Poll::Pending
107 }
108}
109
110// ====================================================================
111
112#[derive(Debug, Clone)]
113pub enum Either4<A, B, C, D> {
114 First(A),
115 Second(B),
116 Third(C),
117 Fourth(D),
118}
119
120/// Same as [`select`], but with more futures.
121pub fn select4<A, B, C, D>(a: A, b: B, c: C, d: D) -> Select4<A, B, C, D>
122where
123 A: Future,
124 B: Future,
125 C: Future,
126 D: Future,
127{
128 Select4 { a, b, c, d }
129}
130
131/// Future for the [`select4`] function.
132#[derive(Debug)]
133#[must_use = "futures do nothing unless you `.await` or poll them"]
134pub struct Select4<A, B, C, D> {
135 a: A,
136 b: B,
137 c: C,
138 d: D,
139}
140
141impl<A, B, C, D> Future for Select4<A, B, C, D>
142where
143 A: Future,
144 B: Future,
145 C: Future,
146 D: Future,
147{
148 type Output = Either4<A::Output, B::Output, C::Output, D::Output>;
149
150 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
151 let this = unsafe { self.get_unchecked_mut() };
152 let a = unsafe { Pin::new_unchecked(&mut this.a) };
153 let b = unsafe { Pin::new_unchecked(&mut this.b) };
154 let c = unsafe { Pin::new_unchecked(&mut this.c) };
155 let d = unsafe { Pin::new_unchecked(&mut this.d) };
156 if let Poll::Ready(x) = a.poll(cx) {
157 return Poll::Ready(Either4::First(x));
158 }
159 if let Poll::Ready(x) = b.poll(cx) {
160 return Poll::Ready(Either4::Second(x));
161 }
162 if let Poll::Ready(x) = c.poll(cx) {
163 return Poll::Ready(Either4::Third(x));
164 }
165 if let Poll::Ready(x) = d.poll(cx) {
166 return Poll::Ready(Either4::Fourth(x));
167 }
168 Poll::Pending
169 }
170}
171
172// ====================================================================
173
174/// Future for the [`select_all`] function.
175#[derive(Debug)]
176#[must_use = "futures do nothing unless you `.await` or poll them"]
177pub struct SelectAll<Fut, const N: usize> {
178 inner: [Fut; N],
179}
180
181/// Creates a new future which will select over a list of futures.
182///
183/// The returned future will wait for any future within `iter` to be ready. Upon
184/// completion the item resolved will be returned, along with the index of the
185/// future that was ready.
186///
187/// # Panics
188///
189/// This function will panic if the array specified contains no items.
190pub fn select_all<Fut: Future, const N: usize>(arr: [Fut; N]) -> SelectAll<Fut, N> {
191 assert!(N > 0);
192 SelectAll { inner: arr }
193}
194
195impl<Fut: Future, const N: usize> Future for SelectAll<Fut, N> {
196 type Output = (Fut::Output, usize);
197
198 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
199 // Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move,
200 // its elements also cannot move. Therefore it is safe to access `inner` and pin
201 // references to the contained futures.
202 let item = unsafe {
203 self.get_unchecked_mut()
204 .inner
205 .iter_mut()
206 .enumerate()
207 .find_map(|(i, f)| match Pin::new_unchecked(f).poll(cx) {
208 Poll::Pending => None,
209 Poll::Ready(e) => Some((i, e)),
210 })
211 };
212
213 match item {
214 Some((idx, res)) => Poll::Ready((res, idx)),
215 None => Poll::Pending,
216 }
217 }
218}
diff --git a/embassy/src/util/select_all.rs b/embassy/src/util/select_all.rs
deleted file mode 100644
index aef22d894..000000000
--- a/embassy/src/util/select_all.rs
+++ /dev/null
@@ -1,58 +0,0 @@
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}
diff --git a/embassy/src/util/steal.rs b/embassy/src/util/steal.rs
new file mode 100644
index 000000000..a0d5f1359
--- /dev/null
+++ b/embassy/src/util/steal.rs
@@ -0,0 +1,3 @@
1pub trait Steal {
2 unsafe fn steal() -> Self;
3}
diff --git a/embassy/src/util/unborrow.rs b/embassy/src/util/unborrow.rs
new file mode 100644
index 000000000..dacfa3d42
--- /dev/null
+++ b/embassy/src/util/unborrow.rs
@@ -0,0 +1,60 @@
1/// Unsafely unborrow an owned singleton out of a `&mut`.
2///
3/// It is intended to be implemented for owned peripheral singletons, such as `USART3` or `AnyPin`.
4/// Unborrowing an owned `T` yields the same `T`. Unborrowing a `&mut T` yields a copy of the T.
5///
6/// This allows writing HAL drivers that either own or borrow their peripherals, but that don't have
7/// to store pointers in the borrowed case.
8///
9/// Safety: this trait can be used to copy non-Copy types. Implementors must not cause
10/// immediate UB when copied, and must not cause UB when copies are later used, provided they
11/// are only used according the [`Self::unborrow`] safety contract.
12///
13pub unsafe trait Unborrow {
14 /// Unborrow result type
15 type Target;
16
17 /// Unborrow a value.
18 ///
19 /// Safety: This returns a copy of a singleton that's normally not
20 /// copiable. The returned copy must ONLY be used while the lifetime of `self` is
21 /// valid, as if it were accessed through `self` every time.
22 unsafe fn unborrow(self) -> Self::Target;
23}
24
25unsafe impl<'a, T: Unborrow> Unborrow for &'a mut T {
26 type Target = T::Target;
27 unsafe fn unborrow(self) -> Self::Target {
28 T::unborrow(core::ptr::read(self))
29 }
30}
31
32macro_rules! unsafe_impl_unborrow_tuples {
33 ($($t:ident),+) => {
34 unsafe impl<$($t),+> Unborrow for ($($t),+)
35 where
36 $(
37 $t: Unborrow<Target = $t>
38 ),+
39 {
40 type Target = ($($t),+);
41 unsafe fn unborrow(self) -> Self::Target {
42 self
43 }
44 }
45
46
47 };
48}
49
50unsafe_impl_unborrow_tuples!(A, B);
51unsafe_impl_unborrow_tuples!(A, B, C);
52unsafe_impl_unborrow_tuples!(A, B, C, D);
53unsafe_impl_unborrow_tuples!(A, B, C, D, E);
54unsafe_impl_unborrow_tuples!(A, B, C, D, E, F);
55unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G);
56unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H);
57unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I);
58unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J);
59unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J, K);
60unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J, K, L);