From d213bba502043aac09a0bdb845278a53ea04f600 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Tue, 6 Aug 2019 17:52:16 -0400 Subject: WIP: stalled out trying to implement const-fn feature. Unfortunately, to maintain API compatibility, `replace` needs to be a regular borrow, so we need interior mutability with `UnsafeCell`. Simultaneously, `HandlerArray` needs to be `const fn` so it can be used where `lazy_static` isn't available, which means it needs to initialize its array in one go without the help of `MaybeUninit`. To do that, `Handler` must be `Copy`, but since it contains an `UnsafeCell` now, it cannot be copy. And thus we are boned. There are times when I think the premise of rust is admirable, but implementation is impossible. --- src/fnnop.rs | 3 ++- src/handler.rs | 27 ++++++++++++++++++++++----- src/lib.rs | 4 ++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/fnnop.rs b/src/fnnop.rs index 871a6ab..13b9379 100644 --- a/src/fnnop.rs +++ b/src/fnnop.rs @@ -2,6 +2,7 @@ // //#![feature(unboxed_closures)] //#![feature(fn_traits)] +use core::cell::UnsafeCell; pub struct FnNOP(); @@ -16,4 +17,4 @@ impl FnOnce<()> for FnNOP { extern "rust-call" fn call_once(self, _args: ()) {} } -static mut NOP: FnNOP = FnNOP(); +pub static mut NOP: UnsafeCell = UnsafeCell::new(FnNOP()); diff --git a/src/handler.rs b/src/handler.rs index 1087b21..ca8aea6 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -85,7 +85,9 @@ //! unsafe { SYSTICK_HANDLER.call() }; //! } //! ``` -#[cfg(not(feature = "const-fn"))] +#[cfg(feature = "const-fn")] +use crate::fnnop::NOP; + use core::cell::UnsafeCell; #[cfg(not(feature = "const-fn"))] use core::ptr::NonNull; @@ -93,7 +95,7 @@ use core::ptr::NonNull; #[cfg(feature = "const-fn")] pub struct Handler<'a> { // Handler that will be executed on `call`. - h: *mut dyn FnMut(), + h: UnsafeCell<*mut dyn FnMut()>, lifetime: core::marker::PhantomData<&'a dyn FnMut()>, } #[cfg(not(feature = "const-fn"))] @@ -108,7 +110,7 @@ impl<'a> Handler<'a> { #[cfg(feature = "const-fn")] pub const fn new() -> Self { Self { - h: &Self::default_handler, + h: UnsafeCell::new(unsafe { NOP.get() }), lifetime: core::marker::PhantomData, } } @@ -130,7 +132,7 @@ impl<'a> Handler<'a> { pub unsafe fn replace(&self, f: &mut (dyn FnMut() + Send + 'a)) { #[cfg(feature = "const-fn")] { - self.h = core::mem::transmute::<_, &'a _>(f); + *self.h.get() = core::mem::transmute::<_, &'a mut _>(f); } #[cfg(not(feature = "const-fn"))] { @@ -150,7 +152,7 @@ impl<'a> Handler<'a> { pub unsafe fn call(&self) { #[cfg(feature = "const-fn")] { - let f: &mut dyn FnMut() = &mut *(self.h as *mut dyn FnMut()); + let f: &mut dyn FnMut() = &mut **self.h.get(); f(); } #[cfg(not(feature = "const-fn"))] @@ -167,6 +169,13 @@ impl<'a> Handler<'a> { } impl<'a> core::fmt::Debug for Handler<'a> { + #[cfg(feature = "const-fn")] + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + let (f0, f1) = unsafe { core::mem::transmute::<_, (usize, usize)>(*self.h.get()) }; + write!(f, "Handler{{ h: (0x{:x}, 0x{:x}) }}", f0, f1) + } + + #[cfg(not(feature = "const-fn"))] fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { let (f0, f1) = unsafe { core::mem::transmute::<_, (usize, usize)>(*self.h.get()) }; write!(f, "Handler{{ h: (0x{:x}, 0x{:x}) }}", f0, f1) @@ -174,6 +183,14 @@ impl<'a> core::fmt::Debug for Handler<'a> { } unsafe impl Sync for Handler<'_> {} +#[cfg(feature = "const-fn")] +impl Copy for Handler<'_> {} +#[cfg(feature = "const-fn")] +impl Clone for Handler<'_> { + fn clone(&self) -> Self { + *self + } +} #[cfg(test)] mod test { diff --git a/src/lib.rs b/src/lib.rs index d0ddad5..4ae3fd1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,9 +16,13 @@ #![no_std] #![cfg_attr(feature = "const-fn", feature(const_fn))] +#![cfg_attr(feature = "const-fn", feature(fn_traits))] +#![cfg_attr(feature = "const-fn", feature(unboxed_closures))] pub mod array; pub mod cs; +#[cfg(feature = "const-fn")] +mod fnnop; pub mod handler; pub use array::HandlerArray; -- cgit v1.2.3