1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#![no_std]
#![doc = include_str!("../README.md")]

use core::sync::atomic::{AtomicUsize, Ordering};

/// The type of an event handler.
///
/// Currently no arguments and return values are supported.
pub type Handler = fn();

/// A lock-free table of event handlers.
///
/// It internally uses an array of `AtomicUsize` to store the handlers.
pub struct HandlerTable<const N: usize> {
    handlers: [AtomicUsize; N],
}

impl<const N: usize> HandlerTable<N> {
    /// Creates a new handler table with all entries empty.
    #[allow(clippy::declare_interior_mutable_const)]
    pub const fn new() -> Self {
        const EMPTY: AtomicUsize = AtomicUsize::new(0);
        Self {
            handlers: [EMPTY; N],
        }
    }

    /// Registers a handler for the given index.
    pub fn register_handler(&self, idx: usize, handler: Handler) -> bool {
        self.handlers[idx]
            .compare_exchange(0, handler as usize, Ordering::Acquire, Ordering::Relaxed)
            .is_ok()
    }

    /// Handles the event with the given index.
    ///
    /// Returns `true` if the event is handled, `false` if no handler is
    /// registered for the given index.
    pub fn handle(&self, idx: usize) -> bool {
        let handler = self.handlers[idx].load(Ordering::Acquire);
        if handler != 0 {
            let handler: Handler = unsafe { core::mem::transmute(handler) };
            handler();
            true
        } else {
            false
        }
    }
}