diff options
author | Brian Cully <bjc@kublai.com> | 2019-07-29 10:48:05 -0400 |
---|---|---|
committer | Brian Cully <bjc@kublai.com> | 2019-07-29 10:48:05 -0400 |
commit | b0c6c4f9a45cf2b965acd3d10499e9df54929b36 (patch) | |
tree | c006650bfb2ff4e233241eb3d5d326cb222daa80 | |
parent | 9a34921b3310a32644ba1ba2e72b028f27d4a2b2 (diff) | |
download | clint-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.toml | 1 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | src/handler.rs | 49 | ||||
-rw-r--r-- | src/lib.rs | 2 |
4 files changed, 46 insertions, 10 deletions
@@ -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. @@ -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() } } @@ -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; |