aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2019-07-29 10:48:05 -0400
committerBrian Cully <bjc@kublai.com>2019-07-29 10:48:05 -0400
commitb0c6c4f9a45cf2b965acd3d10499e9df54929b36 (patch)
treec006650bfb2ff4e233241eb3d5d326cb222daa80
parent9a34921b3310a32644ba1ba2e72b028f27d4a2b2 (diff)
downloadclint-b0c6c4f9a45cf2b965acd3d10499e9df54929b36.tar.gz
clint-b0c6c4f9a45cf2b965acd3d10499e9df54929b36.zip
WIP: Add `const-fn` feature to attempt support for stable toolchain.
To get this to work, either `FnMut` traits need to be allowed in `const fn` in stable, or `Handler::new` needs to be non-`const`.
-rw-r--r--Cargo.toml1
-rw-r--r--README.md4
-rw-r--r--src/handler.rs49
-rw-r--r--src/lib.rs2
4 files changed, 46 insertions, 10 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 1079e1d..6d6f192 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,6 +20,7 @@ cortex-m = "~0.6"
[features]
default = ["isr-32"]
+const-fn = []
# Number of ISR closures to hold in a HandlerTable. This is pretty
# clumsy, but doesn't require const generics.
diff --git a/README.md b/README.md
index c3c6de5..daf4e03 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,10 @@ configure the number of available slots, specify one of the following
cargo features: `isr-8`, `isr-16`, `isr-32`, `isr-64`, `isr-128`, or
`isr-256`. By default, 32 slots are available.
+If you're using a nightly toolchain, you can enable an optimization
+when calling handlers by turning on the `const-fn` feature. This will
+save one conditional branch on every call.
+
# Example Code
See the `examples` directory for some simple examples.
diff --git a/src/handler.rs b/src/handler.rs
index ec1f22e..545e622 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -80,20 +80,35 @@
//! unsafe { SYSTICK_HANDLER.call() };
//! }
//! ```
+#[cfg(not(feature = "const-fn"))]
+use core::ptr::NonNull;
+#[cfg(feature = "const-fn")]
pub struct Handler<'a> {
// Handler that will be executed on `call`.
h: *const dyn FnMut(),
lifetime: core::marker::PhantomData<&'a dyn FnMut()>,
}
+#[cfg(not(feature = "const-fn"))]
+pub struct Handler<'a> {
+ // Handler that will be executed on `call`.
+ h: Option<NonNull<dyn FnMut() + 'a>>,
+}
impl<'a> Handler<'a> {
/// Returns a new Handler that initially does nothing when
/// called. Override its behavior by using `replace`.
pub const fn new() -> Self {
- Self {
- h: &Self::default_handler,
- lifetime: core::marker::PhantomData,
+ #[cfg(feature = "const-fn")]
+ {
+ Self {
+ h: &Self::default_handler,
+ lifetime: core::marker::PhantomData,
+ }
+ }
+ #[cfg(not(feature = "const-fn"))]
+ {
+ Self { h: None }
}
}
@@ -105,7 +120,16 @@ impl<'a> Handler<'a> {
/// while it is being executed. It is your responsibility to make
/// sure that it's not being executed when you call `replace`.
pub unsafe fn replace(&mut self, f: &(dyn FnMut() + Send + 'a)) {
- self.h = core::mem::transmute::<_, &'a _>(f);
+ #[cfg(feature = "const-fn")]
+ {
+ self.h = core::mem::transmute::<_, &'a _>(f);
+ }
+ #[cfg(not(feature = "const-fn"))]
+ {
+ // let ptr: *mut dyn FnMut() = core::mem::transmute::<_, &'a _>(f);
+ // self.h = Some(NonNull::new(ptr));
+ self.h = Some(NonNull::new_unchecked(f));
+ }
}
/// Execute this handler.
@@ -116,8 +140,15 @@ impl<'a> Handler<'a> {
/// closure is being looked up. You need to ensure that `replace`
/// and `call` can not occur at the same time.
pub unsafe fn call(&self) {
- let f: &mut dyn FnMut() = &mut *(self.h as *mut dyn FnMut());
- f();
+ #[cfg(feature = "const-fn")]
+ {
+ let f: &mut dyn FnMut() = &mut *(self.h as *mut dyn FnMut());
+ f();
+ }
+ #[cfg(not(feature = "const-fn"))]
+ {
+ self.h.map(|mut f| (f.as_mut())());
+ }
}
/// Do nothing handler. Needed by `call` until `replace` is used
@@ -152,7 +183,7 @@ mod test {
let mut handler = Handler::new();
unsafe {
- handler.replace(&|| X += 1);
+ handler.replace(&mut || X += 1);
assert_eq!(X, 0);
handler.call();
handler.call();
@@ -166,7 +197,7 @@ mod test {
static mut X: usize = 0;
unsafe {
- HANDLER.replace(&|| X += 1);
+ HANDLER.replace(&mut || X += 1);
assert_eq!(X, 0);
HANDLER.call();
HANDLER.call();
@@ -178,7 +209,7 @@ mod test {
fn replace_with_default() {
let mut handler = Handler::new();
unsafe {
- handler.replace(&Handler::default_handler);
+ handler.replace(&mut Handler::default_handler);
handler.call()
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 8e16b26..d0ddad5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,7 +15,7 @@
//! Critical section support is supplied by the [`cs` module](cs).
#![no_std]
-#![feature(const_fn)]
+#![cfg_attr(feature = "const-fn", feature(const_fn))]
pub mod array;
pub mod cs;