aboutsummaryrefslogtreecommitdiff
path: root/embassy-futures
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-08-22 21:46:09 +0200
committerDario Nieuwenhuis <[email protected]>2022-08-22 22:18:13 +0200
commit21072bee48ff6ec19b79e0d9527ad8cc34a4e9e0 (patch)
treeb5b8c0f4b3571989b5fd15152be5639f4334c282 /embassy-futures
parent61356181b223e95f289ca3af3a038a699cde2112 (diff)
split `embassy-util` into `embassy-futures`, `embassy-sync`.
Diffstat (limited to 'embassy-futures')
-rw-r--r--embassy-futures/Cargo.toml14
-rw-r--r--embassy-futures/src/fmt.rs228
-rw-r--r--embassy-futures/src/lib.rs12
-rw-r--r--embassy-futures/src/select.rs230
-rw-r--r--embassy-futures/src/yield_now.rs25
5 files changed, 509 insertions, 0 deletions
diff --git a/embassy-futures/Cargo.toml b/embassy-futures/Cargo.toml
new file mode 100644
index 000000000..e564f5a96
--- /dev/null
+++ b/embassy-futures/Cargo.toml
@@ -0,0 +1,14 @@
1[package]
2name = "embassy-futures"
3version = "0.1.0"
4edition = "2021"
5
6[package.metadata.embassy_docs]
7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-futures-v$VERSION/embassy-futures/src/"
8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-futures/src/"
9features = ["nightly"]
10target = "thumbv7em-none-eabi"
11
12[dependencies]
13defmt = { version = "0.3", optional = true }
14log = { version = "0.4.14", optional = true }
diff --git a/embassy-futures/src/fmt.rs b/embassy-futures/src/fmt.rs
new file mode 100644
index 000000000..f8bb0a035
--- /dev/null
+++ b/embassy-futures/src/fmt.rs
@@ -0,0 +1,228 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[cfg(feature = "defmt-timestamp-uptime")]
199defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
200
201#[derive(Debug, Copy, Clone, Eq, PartialEq)]
202pub struct NoneError;
203
204pub trait Try {
205 type Ok;
206 type Error;
207 fn into_result(self) -> Result<Self::Ok, Self::Error>;
208}
209
210impl<T> Try for Option<T> {
211 type Ok = T;
212 type Error = NoneError;
213
214 #[inline]
215 fn into_result(self) -> Result<T, NoneError> {
216 self.ok_or(NoneError)
217 }
218}
219
220impl<T, E> Try for Result<T, E> {
221 type Ok = T;
222 type Error = E;
223
224 #[inline]
225 fn into_result(self) -> Self {
226 self
227 }
228}
diff --git a/embassy-futures/src/lib.rs b/embassy-futures/src/lib.rs
new file mode 100644
index 000000000..48c9c8574
--- /dev/null
+++ b/embassy-futures/src/lib.rs
@@ -0,0 +1,12 @@
1#![no_std]
2#![doc = include_str!("../../README.md")]
3#![warn(missing_docs)]
4
5// This mod MUST go first, so that the others see its macros.
6pub(crate) mod fmt;
7
8mod select;
9mod yield_now;
10
11pub use select::*;
12pub use yield_now::*;
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}
diff --git a/embassy-futures/src/yield_now.rs b/embassy-futures/src/yield_now.rs
new file mode 100644
index 000000000..1ebecb916
--- /dev/null
+++ b/embassy-futures/src/yield_now.rs
@@ -0,0 +1,25 @@
1use core::future::Future;
2use core::pin::Pin;
3use core::task::{Context, Poll};
4
5/// Yield from the current task once, allowing other tasks to run.
6pub fn yield_now() -> impl Future<Output = ()> {
7 YieldNowFuture { yielded: false }
8}
9
10struct YieldNowFuture {
11 yielded: bool,
12}
13
14impl Future for YieldNowFuture {
15 type Output = ();
16 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
17 if self.yielded {
18 Poll::Ready(())
19 } else {
20 self.yielded = true;
21 cx.waker().wake_by_ref();
22 Poll::Pending
23 }
24 }
25}