aboutsummaryrefslogtreecommitdiff
path: root/embassy-hal-common
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-07-23 14:00:19 +0200
committerDario Nieuwenhuis <[email protected]>2022-07-23 14:00:19 +0200
commit4901c34d9c4cd326ab9bca02dd099a663da2567f (patch)
tree8225afebb595fb10c1d67148c0d19b7b732853da /embassy-hal-common
parent8a9d2f59af004902d3978a2922843833b98bcce0 (diff)
Rename Unborrowed -> PeripheralRef, Unborrow -> Peripheral
Diffstat (limited to 'embassy-hal-common')
-rw-r--r--embassy-hal-common/src/lib.rs4
-rw-r--r--embassy-hal-common/src/macros.rs14
-rw-r--r--embassy-hal-common/src/peripheral.rs141
-rw-r--r--embassy-hal-common/src/unborrow.rs82
4 files changed, 150 insertions, 91 deletions
diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs
index da7ae9919..d3d9e0a84 100644
--- a/embassy-hal-common/src/lib.rs
+++ b/embassy-hal-common/src/lib.rs
@@ -6,10 +6,10 @@ pub(crate) mod fmt;
6 6
7pub mod drop; 7pub mod drop;
8mod macros; 8mod macros;
9mod peripheral;
9pub mod ratio; 10pub mod ratio;
10pub mod ring_buffer; 11pub mod ring_buffer;
11mod unborrow; 12pub use peripheral::{Peripheral, PeripheralRef};
12pub use unborrow::{Unborrow, Unborrowed};
13 13
14/// Low power blocking wait loop using WFE/SEV. 14/// Low power blocking wait loop using WFE/SEV.
15pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) { 15pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) {
diff --git a/embassy-hal-common/src/macros.rs b/embassy-hal-common/src/macros.rs
index d8e2a06e7..7af85f782 100644
--- a/embassy-hal-common/src/macros.rs
+++ b/embassy-hal-common/src/macros.rs
@@ -21,7 +21,7 @@ macro_rules! peripherals {
21 } 21 }
22 22
23 $(#[$cfg])? 23 $(#[$cfg])?
24 $crate::impl_unborrow!($name); 24 $crate::impl_peripheral!($name);
25 )* 25 )*
26 } 26 }
27 27
@@ -71,22 +71,22 @@ macro_rules! peripherals {
71} 71}
72 72
73#[macro_export] 73#[macro_export]
74macro_rules! unborrow { 74macro_rules! into_ref {
75 ($($name:ident),*) => { 75 ($($name:ident),*) => {
76 $( 76 $(
77 let mut $name = $name.unborrow(); 77 let mut $name = $name.into_ref();
78 )* 78 )*
79 } 79 }
80} 80}
81 81
82#[macro_export] 82#[macro_export]
83macro_rules! impl_unborrow { 83macro_rules! impl_peripheral {
84 ($type:ident) => { 84 ($type:ident) => {
85 impl $crate::Unborrow for $type { 85 impl $crate::Peripheral for $type {
86 type Target = $type; 86 type P = $type;
87 87
88 #[inline] 88 #[inline]
89 unsafe fn unborrow_unchecked(&mut self) -> Self::Target { 89 unsafe fn clone_unchecked(&mut self) -> Self::P {
90 $type { ..*self } 90 $type { ..*self }
91 } 91 }
92 } 92 }
diff --git a/embassy-hal-common/src/peripheral.rs b/embassy-hal-common/src/peripheral.rs
new file mode 100644
index 000000000..620047382
--- /dev/null
+++ b/embassy-hal-common/src/peripheral.rs
@@ -0,0 +1,141 @@
1use core::marker::PhantomData;
2use core::ops::{Deref, DerefMut};
3
4/// An exclusive reference to a peripheral.
5///
6/// This is functionally the same as a `&'a mut T`. The reason for having a
7/// dedicated struct is memory efficiency:
8///
9/// Peripheral singletons are typically either zero-sized (for concrete peripehrals
10/// like `PA9` or `Spi4`) or very small (for example `AnyPin` which is 1 byte).
11/// However `&mut T` is always 4 bytes for 32-bit targets, even if T is zero-sized.
12/// PeripheralRef stores a copy of `T` instead, so it's the same size.
13///
14/// but it is the size of `T` not the size
15/// of a pointer. This is useful if T is a zero sized type.
16pub struct PeripheralRef<'a, T> {
17 inner: T,
18 _lifetime: PhantomData<&'a mut T>,
19}
20
21impl<'a, T> PeripheralRef<'a, T> {
22 #[inline]
23 pub fn new(inner: T) -> Self {
24 Self {
25 inner,
26 _lifetime: PhantomData,
27 }
28 }
29
30 #[inline]
31 pub fn map_into<U>(self) -> PeripheralRef<'a, U>
32 where
33 T: Into<U>,
34 {
35 PeripheralRef {
36 inner: self.inner.into(),
37 _lifetime: PhantomData,
38 }
39 }
40
41 pub unsafe fn into_inner(self) -> T {
42 self.inner
43 }
44}
45
46impl<'a, T> Deref for PeripheralRef<'a, T> {
47 type Target = T;
48
49 #[inline]
50 fn deref(&self) -> &Self::Target {
51 &self.inner
52 }
53}
54
55impl<'a, T> DerefMut for PeripheralRef<'a, T> {
56 #[inline]
57 fn deref_mut(&mut self) -> &mut Self::Target {
58 &mut self.inner
59 }
60}
61
62/// Trait for any type that can be used as a peripheral of type `P`.
63///
64/// This is used in driver constructors, to allow passing either owned peripherals (e.g. `TWISPI0`),
65/// or borrowed peripherals (e.g. `&mut TWISPI0`).
66///
67/// For example, if you have a driver with a constructor like this:
68///
69/// ```ignore
70/// impl<'d, T: Instance> Twim<'d, T> {
71/// pub fn new(
72/// twim: impl Peripheral<P = T> + 'd,
73/// irq: impl Peripheral<P = T::Interrupt> + 'd,
74/// sda: impl Peripheral<P = impl GpioPin> + 'd,
75/// scl: impl Peripheral<P = impl GpioPin> + 'd,
76/// config: Config,
77/// ) -> Self { .. }
78/// }
79/// ```
80///
81/// You may call it with owned peripherals, which yields an instance that can live forever (`'static`):
82///
83/// ```ignore
84/// let mut twi: Twim<'static, ...> = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
85/// ```
86///
87/// Or you may call it with borrowed peripherals, which yields an instance that can only live for as long
88/// as the borrows last:
89///
90/// ```ignore
91/// let mut twi: Twim<'_, ...> = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
92/// ```
93///
94/// # Implementation details, for HAL authors
95///
96/// When writing a HAL, the intended way to use this trait is to take `impl Peripheral<P = ..>` in
97/// the HAL's public API (such as driver constructors), calling `.into_ref()` to obtain a `PeripheralRef`,
98/// and storing that in the driver struct.
99///
100/// `.into_ref()` on an owned `T` yields a `PeripheralRef<'static, T>`.
101/// `.into_ref()` on an `&'a mut T` yields a `PeripheralRef<'a, T>`.
102pub trait Peripheral: Sized {
103 /// Peripheral singleton type
104 type P;
105
106 /// Unsafely clone (duplicate) a peripheral singleton.
107 ///
108 /// # Safety
109 ///
110 /// This returns an owned clone of the peripheral. You must manually ensure
111 /// only one copy of the peripheral is in use at a time. For example, don't
112 /// create two SPI drivers on `SPI1`, because they will "fight" each other.
113 ///
114 /// You should strongly prefer using `into_ref()` instead. It returns a
115 /// `PeripheralRef`, which allows the borrow checker to enforce this at compile time.
116 unsafe fn clone_unchecked(&mut self) -> Self::P;
117
118 /// Convert a value into a `PeripheralRef`.
119 ///
120 /// When called on an owned `T`, yields a `PeripheralRef<'static, T>`.
121 /// When called on an `&'a mut T`, yields a `PeripheralRef<'a, T>`.
122 #[inline]
123 fn into_ref<'a>(mut self) -> PeripheralRef<'a, Self::P>
124 where
125 Self: 'a,
126 {
127 PeripheralRef::new(unsafe { self.clone_unchecked() })
128 }
129}
130
131impl<'b, T: DerefMut> Peripheral for T
132where
133 T::Target: Peripheral,
134{
135 type P = <T::Target as Peripheral>::P;
136
137 #[inline]
138 unsafe fn clone_unchecked(&mut self) -> Self::P {
139 self.deref_mut().clone_unchecked()
140 }
141}
diff --git a/embassy-hal-common/src/unborrow.rs b/embassy-hal-common/src/unborrow.rs
deleted file mode 100644
index 06e8d0c82..000000000
--- a/embassy-hal-common/src/unborrow.rs
+++ /dev/null
@@ -1,82 +0,0 @@
1use core::marker::PhantomData;
2use core::ops::{Deref, DerefMut};
3
4/// This is essentially a `&mut T`, but it is the size of `T` not the size
5/// of a pointer. This is useful if T is a zero sized type.
6pub struct Unborrowed<'a, T> {
7 inner: T,
8 _lifetime: PhantomData<&'a mut T>,
9}
10
11impl<'a, T> Unborrowed<'a, T> {
12 pub fn new(inner: T) -> Self {
13 Self {
14 inner,
15 _lifetime: PhantomData,
16 }
17 }
18
19 pub fn map_into<U>(self) -> Unborrowed<'a, U>
20 where
21 T: Into<U>,
22 {
23 Unborrowed {
24 inner: self.inner.into(),
25 _lifetime: PhantomData,
26 }
27 }
28
29 pub unsafe fn into_inner(self) -> T {
30 self.inner
31 }
32}
33
34impl<'a, T> Deref for Unborrowed<'a, T> {
35 type Target = T;
36
37 fn deref(&self) -> &Self::Target {
38 &self.inner
39 }
40}
41
42impl<'a, T> DerefMut for Unborrowed<'a, T> {
43 fn deref_mut(&mut self) -> &mut Self::Target {
44 &mut self.inner
45 }
46}
47
48/// Unsafely unborrow an owned singleton out of a `&mut`.
49///
50/// It is intended to be implemented for owned peripheral singletons, such as `USART3` or `AnyPin`.
51/// Unborrowing an owned `T` yields an `Unborrowed<'static, T>`.
52/// Unborrowing a `&'a mut T` yields an `Unborrowed<'a, T>`.
53///
54/// This allows writing HAL drivers that either own or borrow their peripherals, but that don't have
55/// to store pointers in the borrowed case.
56pub trait Unborrow: Sized {
57 /// Unborrow result type
58 type Target;
59
60 unsafe fn unborrow_unchecked(&mut self) -> Self::Target;
61
62 /// Unborrow a value.
63 #[inline]
64 fn unborrow<'a>(mut self) -> Unborrowed<'a, Self::Target>
65 where
66 Self: 'a,
67 {
68 Unborrowed::new(unsafe { self.unborrow_unchecked() })
69 }
70}
71
72impl<'b, T: DerefMut> Unborrow for T
73where
74 T::Target: Unborrow,
75{
76 type Target = <T::Target as Unborrow>::Target;
77
78 #[inline]
79 unsafe fn unborrow_unchecked(&mut self) -> Self::Target {
80 self.deref_mut().unborrow_unchecked()
81 }
82}