From c8bd792b7abf3bbb0c713a07e58906e9c690a320 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 5 Apr 2022 21:17:29 +0200 Subject: [PATCH 1/4] reorganize `util` mod. --- embassy/src/util/mod.rs | 73 ++----------------- embassy/src/util/{select_all.rs => select.rs} | 0 embassy/src/util/steal.rs | 3 + embassy/src/util/unborrow.rs | 60 +++++++++++++++ 4 files changed, 69 insertions(+), 67 deletions(-) rename embassy/src/util/{select_all.rs => select.rs} (100%) create mode 100644 embassy/src/util/steal.rs create mode 100644 embassy/src/util/unborrow.rs diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index f5cc9623..928edf0e 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs @@ -1,74 +1,13 @@ //! Misc utilities mod forever; -mod select_all; +mod select; +mod steal; +mod unborrow; mod yield_now; pub use forever::*; -pub use select_all::*; +pub use select::*; +pub use steal::*; +pub use unborrow::*; pub use yield_now::*; - -/// Unsafely unborrow an owned singleton out of a `&mut`. -/// -/// It is intended to be implemented for owned peripheral singletons, such as `USART3` or `AnyPin`. -/// Unborrowing an owned `T` yields the same `T`. Unborrowing a `&mut T` yields a copy of the T. -/// -/// This allows writing HAL drivers that either own or borrow their peripherals, but that don't have -/// to store pointers in the borrowed case. -/// -/// Safety: this trait can be used to copy non-Copy types. Implementors must not cause -/// immediate UB when copied, and must not cause UB when copies are later used, provided they -/// are only used according the [`Self::unborrow`] safety contract. -/// -pub unsafe trait Unborrow { - /// Unborrow result type - type Target; - - /// Unborrow a value. - /// - /// Safety: This returns a copy of a singleton that's normally not - /// copiable. The returned copy must ONLY be used while the lifetime of `self` is - /// valid, as if it were accessed through `self` every time. - unsafe fn unborrow(self) -> Self::Target; -} - -unsafe impl<'a, T: Unborrow> Unborrow for &'a mut T { - type Target = T::Target; - unsafe fn unborrow(self) -> Self::Target { - T::unborrow(core::ptr::read(self)) - } -} - -pub trait Steal { - unsafe fn steal() -> Self; -} - -macro_rules! unsafe_impl_unborrow_tuples { - ($($t:ident),+) => { - unsafe impl<$($t),+> Unborrow for ($($t),+) - where - $( - $t: Unborrow - ),+ - { - type Target = ($($t),+); - unsafe fn unborrow(self) -> Self::Target { - self - } - } - - - }; -} - -unsafe_impl_unborrow_tuples!(A, B); -unsafe_impl_unborrow_tuples!(A, B, C); -unsafe_impl_unborrow_tuples!(A, B, C, D); -unsafe_impl_unborrow_tuples!(A, B, C, D, E); -unsafe_impl_unborrow_tuples!(A, B, C, D, E, F); -unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G); -unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H); -unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I); -unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J); -unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J, K); -unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J, K, L); diff --git a/embassy/src/util/select_all.rs b/embassy/src/util/select.rs similarity index 100% rename from embassy/src/util/select_all.rs rename to embassy/src/util/select.rs diff --git a/embassy/src/util/steal.rs b/embassy/src/util/steal.rs new file mode 100644 index 00000000..a0d5f135 --- /dev/null +++ b/embassy/src/util/steal.rs @@ -0,0 +1,3 @@ +pub trait Steal { + unsafe fn steal() -> Self; +} diff --git a/embassy/src/util/unborrow.rs b/embassy/src/util/unborrow.rs new file mode 100644 index 00000000..dacfa3d4 --- /dev/null +++ b/embassy/src/util/unborrow.rs @@ -0,0 +1,60 @@ +/// Unsafely unborrow an owned singleton out of a `&mut`. +/// +/// It is intended to be implemented for owned peripheral singletons, such as `USART3` or `AnyPin`. +/// Unborrowing an owned `T` yields the same `T`. Unborrowing a `&mut T` yields a copy of the T. +/// +/// This allows writing HAL drivers that either own or borrow their peripherals, but that don't have +/// to store pointers in the borrowed case. +/// +/// Safety: this trait can be used to copy non-Copy types. Implementors must not cause +/// immediate UB when copied, and must not cause UB when copies are later used, provided they +/// are only used according the [`Self::unborrow`] safety contract. +/// +pub unsafe trait Unborrow { + /// Unborrow result type + type Target; + + /// Unborrow a value. + /// + /// Safety: This returns a copy of a singleton that's normally not + /// copiable. The returned copy must ONLY be used while the lifetime of `self` is + /// valid, as if it were accessed through `self` every time. + unsafe fn unborrow(self) -> Self::Target; +} + +unsafe impl<'a, T: Unborrow> Unborrow for &'a mut T { + type Target = T::Target; + unsafe fn unborrow(self) -> Self::Target { + T::unborrow(core::ptr::read(self)) + } +} + +macro_rules! unsafe_impl_unborrow_tuples { + ($($t:ident),+) => { + unsafe impl<$($t),+> Unborrow for ($($t),+) + where + $( + $t: Unborrow + ),+ + { + type Target = ($($t),+); + unsafe fn unborrow(self) -> Self::Target { + self + } + } + + + }; +} + +unsafe_impl_unborrow_tuples!(A, B); +unsafe_impl_unborrow_tuples!(A, B, C); +unsafe_impl_unborrow_tuples!(A, B, C, D); +unsafe_impl_unborrow_tuples!(A, B, C, D, E); +unsafe_impl_unborrow_tuples!(A, B, C, D, E, F); +unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G); +unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H); +unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I); +unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J); +unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J, K); +unsafe_impl_unborrow_tuples!(A, B, C, D, E, F, G, H, I, J, K, L); From 59ec634246251d9ad0487a71c7d1ee2f70b33c57 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 5 Apr 2022 21:20:44 +0200 Subject: [PATCH 2/4] Remove SelectAll::into_inner. Due to not requiring Unpin, it's not really possible to call it after having polled it, you can only call it right after constructing it, so in practice it's not very useful. --- embassy/src/util/select.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/embassy/src/util/select.rs b/embassy/src/util/select.rs index aef22d89..29e17968 100644 --- a/embassy/src/util/select.rs +++ b/embassy/src/util/select.rs @@ -25,13 +25,6 @@ pub fn select_all(arr: [Fut; N]) -> SelectAll 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); From b5c479fdad023ee4f28181965b04f55e5e41f62f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 5 Apr 2022 21:22:02 +0200 Subject: [PATCH 3/4] Remove impl Unpin for SelectAll, as it's automatically inferred. --- embassy/src/util/select.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy/src/util/select.rs b/embassy/src/util/select.rs index 29e17968..b3b03d81 100644 --- a/embassy/src/util/select.rs +++ b/embassy/src/util/select.rs @@ -9,8 +9,6 @@ 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 From f32fa1d33ae04274e831b30028f5e2747fbb0d05 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 5 Apr 2022 21:51:43 +0200 Subject: [PATCH 4/4] Add select, select3, select4. --- embassy/src/util/select.rs | 169 +++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/embassy/src/util/select.rs b/embassy/src/util/select.rs index b3b03d81..ccc50f11 100644 --- a/embassy/src/util/select.rs +++ b/embassy/src/util/select.rs @@ -2,6 +2,175 @@ use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll}; +#[derive(Debug, Clone)] +pub enum Either { + First(A), + Second(B), +} + +/// Wait for one of two futures to complete. +/// +/// This function returns a new future which polls all the futures. +/// When one of them completes, it will complete with its result value. +/// +/// The other future is dropped. +pub fn select(a: A, b: B) -> Select +where + A: Future, + B: Future, +{ + Select { a, b } +} + +/// Future for the [`select`] function. +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Select { + a: A, + b: B, +} + +impl Unpin for Select {} + +impl Future for Select +where + A: Future, + B: Future, +{ + type Output = Either; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = unsafe { self.get_unchecked_mut() }; + let a = unsafe { Pin::new_unchecked(&mut this.a) }; + let b = unsafe { Pin::new_unchecked(&mut this.b) }; + if let Poll::Ready(x) = a.poll(cx) { + return Poll::Ready(Either::First(x)); + } + if let Poll::Ready(x) = b.poll(cx) { + return Poll::Ready(Either::Second(x)); + } + Poll::Pending + } +} + +// ==================================================================== + +#[derive(Debug, Clone)] +pub enum Either3 { + First(A), + Second(B), + Third(C), +} + +/// Same as [`select`], but with more futures. +pub fn select3(a: A, b: B, c: C) -> Select3 +where + A: Future, + B: Future, + C: Future, +{ + Select3 { a, b, c } +} + +/// Future for the [`select3`] function. +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Select3 { + a: A, + b: B, + c: C, +} + +impl Future for Select3 +where + A: Future, + B: Future, + C: Future, +{ + type Output = Either3; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = unsafe { self.get_unchecked_mut() }; + let a = unsafe { Pin::new_unchecked(&mut this.a) }; + let b = unsafe { Pin::new_unchecked(&mut this.b) }; + let c = unsafe { Pin::new_unchecked(&mut this.c) }; + if let Poll::Ready(x) = a.poll(cx) { + return Poll::Ready(Either3::First(x)); + } + if let Poll::Ready(x) = b.poll(cx) { + return Poll::Ready(Either3::Second(x)); + } + if let Poll::Ready(x) = c.poll(cx) { + return Poll::Ready(Either3::Third(x)); + } + Poll::Pending + } +} + +// ==================================================================== + +#[derive(Debug, Clone)] +pub enum Either4 { + First(A), + Second(B), + Third(C), + Fourth(D), +} + +/// Same as [`select`], but with more futures. +pub fn select4(a: A, b: B, c: C, d: D) -> Select4 +where + A: Future, + B: Future, + C: Future, + D: Future, +{ + Select4 { a, b, c, d } +} + +/// Future for the [`select4`] function. +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Select4 { + a: A, + b: B, + c: C, + d: D, +} + +impl Future for Select4 +where + A: Future, + B: Future, + C: Future, + D: Future, +{ + type Output = Either4; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = unsafe { self.get_unchecked_mut() }; + let a = unsafe { Pin::new_unchecked(&mut this.a) }; + let b = unsafe { Pin::new_unchecked(&mut this.b) }; + let c = unsafe { Pin::new_unchecked(&mut this.c) }; + let d = unsafe { Pin::new_unchecked(&mut this.d) }; + if let Poll::Ready(x) = a.poll(cx) { + return Poll::Ready(Either4::First(x)); + } + if let Poll::Ready(x) = b.poll(cx) { + return Poll::Ready(Either4::Second(x)); + } + if let Poll::Ready(x) = c.poll(cx) { + return Poll::Ready(Either4::Third(x)); + } + if let Poll::Ready(x) = d.poll(cx) { + return Poll::Ready(Either4::Fourth(x)); + } + Poll::Pending + } +} + +// ==================================================================== + /// Future for the [`select_all`] function. #[derive(Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"]