use crate::cs::{CriticalSection, Locker};
use crate::Handler;
use core::cell::UnsafeCell;
#[cfg(feature = "isr-8")]
const NR_ISR: usize = 8;
#[cfg(feature = "isr-16")]
const NR_ISR: usize = 16;
#[cfg(feature = "isr-32")]
const NR_ISR: usize = 32;
#[cfg(feature = "isr-64")]
const NR_ISR: usize = 64;
#[cfg(feature = "isr-128")]
const NR_ISR: usize = 128;
#[cfg(feature = "isr-256")]
const NR_ISR: usize = 256;
#[derive(Debug)]
pub struct HandlerArray<'a> {
h: UnsafeCell<[Handler<'a>; NR_ISR]>,
}
impl<'a> HandlerArray<'a> {
pub const fn new() -> Self {
Self {
h: UnsafeCell::new([Handler::new(); NR_ISR]),
}
}
pub fn register<F>(&self, nr: usize, f: &'a mut F)
where
F: FnMut() + Send + 'a,
{
self.lock_register(&Locker::new(), nr, f)
}
pub fn lock_register<F, CS>(&self, cs: &CS, nr: usize, f: &'a mut F)
where
F: FnMut() + Send + 'a,
CS: CriticalSection,
{
cs.with_lock(|| unsafe { (*self.h.get())[nr].replace(f) });
}
pub fn call(&self, nr: usize) {
unsafe { (*self.h.get())[nr].call() }
}
pub fn with_overrides<'b>(&self, f: impl FnOnce(&HandlerArray<'b>)) {
self.lock_overrides(&Locker::new(), f)
}
pub fn lock_overrides<'b, CS>(&self, cs: &CS, f: impl FnOnce(&HandlerArray<'b>))
where
CS: CriticalSection,
{
let tmp: &HandlerArray<'b> = unsafe { core::mem::transmute(self) };
let bk = HandlerArray::new();
unsafe { core::ptr::copy_nonoverlapping(tmp.h.get(), bk.h.get(), 1) }
f(tmp);
cs.with_lock(|| unsafe { core::ptr::copy_nonoverlapping(bk.h.get(), tmp.h.get(), 1) });
}
}
unsafe impl<'a> Sync for HandlerArray<'a> {}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn overrides_unwind() {
static mut CALLS: usize = 0;
let mut cl = || unsafe { CALLS += 1 };
let cl_ref = &mut cl;
let ht = HandlerArray::new();
ht.with_overrides(|t| {
t.register(0, cl_ref);
ht.call(0);
});
unsafe { assert_eq!(CALLS, 1) };
ht.call(0);
unsafe { assert_eq!(CALLS, 1) };
}
}