Skip to content

Commit 46916ed

Browse files
committed
Allow calling interrupt::free with zero-arity closures.
1 parent b581ec7 commit 46916ed

File tree

6 files changed

+45
-10
lines changed

6 files changed

+45
-10
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Changed
11+
- `interrupt::free` can be called with closures of type `FnOnce() -> T`.
12+
1013
### Deprecated
1114
- the `ptr()` function on all peripherals register blocks in favor of
1215
the associated constant `PTR` (#386).
16+
- Calling `interrupt::free` with closures of type `FnOnce(&CriticalSection) -> T` is deprecated. Users should switch to using `critical_section::with`.
1317

1418
## [v0.7.4] - 2021-12-31
1519

src/interrupt.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,54 @@ pub unsafe fn enable() {
4848
call_asm!(__cpsie());
4949
}
5050

51+
/// Hacky compatibility layer to allow calling `interrupt::free` using
52+
/// closures with arity 0 as well as 1. This trait is not considered
53+
/// part of the public API.
54+
///
55+
/// The generic `Args` type is not actually used, see:
56+
/// https://geo-ant.github.io/blog/2021/rust-traits-and-variadic-functions/
57+
///
58+
/// TODO: Remove before releasing 0.8.
59+
pub trait InterruptFreeFn<Args, R> {
60+
/// Call the closure.
61+
unsafe fn call(self) -> R;
62+
}
63+
64+
impl<F, R> InterruptFreeFn<(), R> for F
65+
where
66+
F: FnOnce() -> R,
67+
{
68+
#[inline]
69+
unsafe fn call(self) -> R {
70+
self()
71+
}
72+
}
73+
74+
impl<'cs, F, R> InterruptFreeFn<&'cs CriticalSection, R> for F
75+
where
76+
F: FnOnce(&'cs CriticalSection) -> R,
77+
{
78+
#[inline]
79+
unsafe fn call(self) -> R {
80+
let cs: &'cs CriticalSection = core::mem::transmute(&CriticalSection::new());
81+
self(cs)
82+
}
83+
}
84+
5185
/// Execute closure `f` in an interrupt-free context.
5286
///
5387
/// This as also known as a "critical section".
5488
#[inline]
55-
pub fn free<F, R>(f: F) -> R
89+
pub fn free<Args, F, R>(f: F) -> R
5690
where
57-
F: FnOnce(&CriticalSection) -> R,
91+
F: InterruptFreeFn<Args, R>,
5892
{
5993
let primask = crate::register::primask::read();
6094

6195
// disable interrupts
6296
disable();
6397

64-
let r = f(unsafe { &CriticalSection::new() });
98+
let r = unsafe { f.call() };
6599

66100
// If the interrupts were active before our `disable` call, then re-enable
67101
// them. Otherwise, keep them disabled

src/lib.rs

-3
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,6 @@
7979
// Don't warn about feature(asm) being stable on Rust >= 1.59.0
8080
#![allow(stable_features)]
8181

82-
extern crate bare_metal;
83-
extern crate volatile_register;
84-
8582
#[macro_use]
8683
mod call_asm;
8784
#[macro_use]

src/macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ macro_rules! iprintln {
5454
#[macro_export]
5555
macro_rules! singleton {
5656
(: $ty:ty = $expr:expr) => {
57-
$crate::interrupt::free(|_| {
57+
$crate::interrupt::free(|| {
5858
static mut VAR: Option<$ty> = None;
5959

6060
#[allow(unsafe_code)]

src/peripheral/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl Peripherals {
165165
/// Returns all the core peripherals *once*
166166
#[inline]
167167
pub fn take() -> Option<Self> {
168-
interrupt::free(|_| {
168+
interrupt::free(|| {
169169
if unsafe { TAKEN } {
170170
None
171171
} else {

src/peripheral/sau.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ impl SAU {
162162
/// This function is executed under a critical section to prevent having inconsistent results.
163163
#[inline]
164164
pub fn set_region(&mut self, region_number: u8, region: SauRegion) -> Result<(), SauError> {
165-
interrupt::free(|_| {
165+
interrupt::free(|| {
166166
let base_address = region.base_address;
167167
let limit_address = region.limit_address;
168168
let attribute = region.attribute;
@@ -215,7 +215,7 @@ impl SAU {
215215
/// This function is executed under a critical section to prevent having inconsistent results.
216216
#[inline]
217217
pub fn get_region(&mut self, region_number: u8) -> Result<SauRegion, SauError> {
218-
interrupt::free(|_| {
218+
interrupt::free(|| {
219219
if region_number >= self.region_numbers() {
220220
Err(SauError::RegionNumberTooBig)
221221
} else {

0 commit comments

Comments
 (0)