aboutsummaryrefslogtreecommitdiff
path: root/embassy-extras/src/peripheral_shared.rs
diff options
context:
space:
mode:
authorLiam Murphy <[email protected]>2021-07-29 15:11:26 +1000
committerLiam Murphy <[email protected]>2021-07-29 15:11:26 +1000
commitd5ba35424d7eef2cc0c501758d214ce3a6febfc1 (patch)
tree8d3b07073b7f5f2ea67bb061a990b019c79aeeb5 /embassy-extras/src/peripheral_shared.rs
parent4d9514cbcb97343c3a75bfa565d753c44c2a0e27 (diff)
Replace `PeripheralStateUnchecked` with `register_interrupt_unchecked`
Diffstat (limited to 'embassy-extras/src/peripheral_shared.rs')
-rw-r--r--embassy-extras/src/peripheral_shared.rs52
1 files changed, 33 insertions, 19 deletions
diff --git a/embassy-extras/src/peripheral_shared.rs b/embassy-extras/src/peripheral_shared.rs
index 788ac3f96..71d746341 100644
--- a/embassy-extras/src/peripheral_shared.rs
+++ b/embassy-extras/src/peripheral_shared.rs
@@ -5,30 +5,19 @@ use embassy::interrupt::{Interrupt, InterruptExt};
5 5
6use crate::peripheral::can_be_preempted; 6use crate::peripheral::can_be_preempted;
7 7
8/// A version of `PeripheralState` without the `'static` bound,
9/// for cases where the compiler can't statically make sure
10/// that `on_interrupt` doesn't reference anything which might be invalidated.
11///
12/// # Safety
13/// When types implementing this trait are used with `Peripheral`,
14/// no fields referenced by `on_interrupt`'s lifetimes must end without first calling `Drop` on the `Peripheral`.
15pub unsafe trait PeripheralStateUnchecked: Sync {
16 type Interrupt: Interrupt;
17 fn on_interrupt(&self);
18}
19
20/// A type which can be used as state with `Peripheral`. 8/// A type which can be used as state with `Peripheral`.
21/// 9///
22/// It needs to be `Sync` because references are shared between the 'thread' which owns the `Peripheral` and the interrupt. 10/// It needs to be `Sync` because references are shared between the 'thread' which owns the `Peripheral` and the interrupt.
23/// 11///
24/// It also requires `'static`, because although `Pin` guarantees that the memory of the state won't be invalidated, 12/// It also requires `'static` to be used safely with `Peripheral::register_interrupt`,
13/// because although `Pin` guarantees that the memory of the state won't be invalidated,
25/// it doesn't guarantee that the lifetime will last. 14/// it doesn't guarantee that the lifetime will last.
26pub trait PeripheralState: Sync + 'static { 15pub trait PeripheralState: Sync {
27 type Interrupt: Interrupt; 16 type Interrupt: Interrupt;
28 fn on_interrupt(&self); 17 fn on_interrupt(&self);
29} 18}
30 19
31pub struct Peripheral<S: PeripheralStateUnchecked> { 20pub struct Peripheral<S: PeripheralState> {
32 state: S, 21 state: S,
33 22
34 irq_setup_done: bool, 23 irq_setup_done: bool,
@@ -38,7 +27,24 @@ pub struct Peripheral<S: PeripheralStateUnchecked> {
38 _pinned: PhantomPinned, 27 _pinned: PhantomPinned,
39} 28}
40 29
41impl<S: PeripheralStateUnchecked> Peripheral<S> { 30impl<S: PeripheralState + 'static> Peripheral<S> {
31 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it.
32 ///
33 /// This requires this `Peripheral`'s `PeripheralState` to live for `'static`,
34 /// because `Pin` only guarantees that it's memory won't be repurposed,
35 /// not that it's lifetime will last.
36 ///
37 /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`.
38 ///
39 /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`;
40 /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`.
41 pub fn register_interrupt(self: Pin<&mut Self>) {
42 // SAFETY: `S: 'static`, so there's no way it's lifetime can expire.
43 unsafe { self.register_interrupt_unchecked() }
44 }
45}
46
47impl<S: PeripheralState> Peripheral<S> {
42 pub fn new(irq: S::Interrupt, state: S) -> Self { 48 pub fn new(irq: S::Interrupt, state: S) -> Self {
43 if can_be_preempted(&irq) { 49 if can_be_preempted(&irq) {
44 panic!("`Peripheral` cannot be created in an interrupt with higher priority than the interrupt it wraps"); 50 panic!("`Peripheral` cannot be created in an interrupt with higher priority than the interrupt it wraps");
@@ -54,8 +60,16 @@ impl<S: PeripheralStateUnchecked> Peripheral<S> {
54 } 60 }
55 } 61 }
56 62
57 pub fn register_interrupt(self: Pin<&mut Self>) { 63 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it.
58 let this = unsafe { self.get_unchecked_mut() }; 64 ///
65 /// # Safety
66 /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler
67 /// must not end without `Drop` being called on this `Peripheral`.
68 ///
69 /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`,
70 /// or making sure that nothing like `mem::forget` is used on the `Peripheral`.
71 pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) {
72 let this = self.get_unchecked_mut();
59 if this.irq_setup_done { 73 if this.irq_setup_done {
60 return; 74 return;
61 } 75 }
@@ -100,7 +114,7 @@ impl<S: PeripheralStateUnchecked> Peripheral<S> {
100 } 114 }
101} 115}
102 116
103impl<S: PeripheralStateUnchecked> Drop for Peripheral<S> { 117impl<S: PeripheralState> Drop for Peripheral<S> {
104 fn drop(&mut self) { 118 fn drop(&mut self) {
105 self.irq.disable(); 119 self.irq.disable();
106 self.irq.remove_handler(); 120 self.irq.remove_handler();