ek-event 0.1.1

Self-contained event engine in Rust, a faithful semantic replication of enkeep_trade's event engine. No dependency on enkeep_trade.
Documentation
//! handler 注册表:`RwLock<精确表 + general 表>`,HandlerId 去重。
//!
//! 原版差异:
//! - 原版 `defaultdict(list)` + `list[handler]`(对象相等去重)在 Rust 不可复刻(闭包不可比),
//!   改为注册时分配自增 [`HandlerId`],上层可保存 id 用于注销。
//! - 全程 RwLock 保护(原版无锁靠 GIL,这里修正)。

use crate::event::Event;
use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, RwLock};

/// handler 函数签名(与原版 `Callable[[Event], None]` 对齐)。
pub type HandlerFn = Arc<dyn Fn(&Event) + Send + Sync>;

/// 注册标识;unregister 凭它定位。
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct HandlerId(pub(crate) u64);

struct Registered {
    id: HandlerId,
    f: HandlerFn,
}

#[derive(Default)]
struct Table {
    /// event_type -> 按注册顺序的 handler 列表(精确匹配分发)。
    typed: HashMap<String, Vec<Registered>>,
    /// 通用 handler 列表(收所有事件,在 type handler 之后执行)。
    general: Vec<Registered>,
}

/// handler 注册管理器。线程安全。(含不透明函数对象,不 derive Debug)
#[derive(Default)]
pub struct HandlerRegistry {
    table: RwLock<Table>,
    next_id: AtomicU64,
}

impl HandlerRegistry {
    /// 注册 handler 至指定 event_type,返回全局唯一 [`HandlerId`] 供注销。
    /// 注意:每次注册都会新增一条(闭包不可比较,原版"函数相等去重"无法复刻);
    /// 防重复注册由调用方负责,引擎只保证 id 唯一且可精确注销。
    pub fn register(&self, event_type: impl Into<String>, f: HandlerFn) -> HandlerId {
        let id = HandlerId(self.next_id.fetch_add(1, Ordering::Relaxed));
        let mut t = self.table.write().unwrap();
        t.typed
            .entry(event_type.into())
            .or_default()
            .push(Registered { id, f });
        id
    }

    /// 注销 HandlerId,无论挂在哪个 type 下;true 表示确实注销了某个。
    /// 类型列表变空时自动从表中移除该 type(对齐原版 `pop(type)`)。
    pub fn unregister(&self, id: HandlerId) -> bool {
        let mut t = self.table.write().unwrap();
        let mut removed = false;
        for (_, list) in t.typed.iter_mut() {
            if let Some(pos) = list.iter().position(|r| r.id == id) {
                list.remove(pos);
                removed = true;
            }
        }
        t.typed.retain(|_, l| !l.is_empty());
        if !removed {
            let before = t.general.len();
            t.general.retain(|r| r.id != id);
            removed = before != t.general.len();
        }
        removed
    }

    /// 注册通用 handler;成功返回 HandlerId。
    pub fn register_general(&self, f: HandlerFn) -> HandlerId {
        let id = HandlerId(self.next_id.fetch_add(1, Ordering::Relaxed));
        self.table
            .write()
            .unwrap()
            .general
            .push(Registered { id, f });
        id
    }

    /// 注销通用 handler。
    pub fn unregister_general(&self, id: HandlerId) -> bool {
        let mut t = self.table.write().unwrap();
        let before = t.general.len();
        t.general.retain(|r| r.id != id);
        before != t.general.len()
    }

    /// 取指定 event_type 的 handler 快照(供分发线程无锁执行)。
    pub(crate) fn snapshot(&self, event_type: &str) -> Vec<HandlerFn> {
        let t = self.table.read().unwrap();
        let mut out = Vec::new();
        if let Some(list) = t.typed.get(event_type) {
            out.extend(list.iter().map(|r| r.f.clone()));
        }
        out.extend(t.general.iter().map(|r| r.f.clone()));
        out
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::atomic::AtomicUsize;

    #[test]
    fn dispatch_and_unregister() {
        let reg = HandlerRegistry::default();
        let cnt = Arc::new(AtomicUsize::new(0));
        let c1 = cnt.clone();
        let id1 = reg.register(
            "eTick.",
            Arc::new(move |_| {
                c1.fetch_add(1, Ordering::SeqCst);
            }),
        );
        let c2 = cnt.clone();
        let id2 = reg.register(
            "eTick.",
            Arc::new(move |_| {
                c2.fetch_add(1, Ordering::SeqCst);
            }),
        );
        // general
        let c3 = cnt.clone();
        let g = reg.register_general(Arc::new(move |_| {
            c3.fetch_add(10, Ordering::SeqCst);
        }));
        let snap = reg.snapshot("eTick.");
        assert_eq!(snap.len(), 3, "2 typed + 1 general");
        assert_eq!(cnt.load(Ordering::SeqCst), 0);

        // 注销后快照变化
        assert!(reg.unregister(g));
        assert!(!reg.unregister(g));
        let snap = reg.snapshot("eTick.");
        assert_eq!(snap.len(), 2, "general withdrawn");
        assert!(reg.unregister(id1));
        assert!(reg.unregister(id2));
        // (T2)全部注销后,type 表自动回收:快照为空
        let snap = reg.snapshot("eTick.");
        assert!(snap.is_empty(), "empty handler list should be recycled");
        // 空表回收后重新注册该 type,列表重建、正常可分发
        let c4 = cnt.clone();
        let id_re = reg.register(
            "eTick.",
            Arc::new(move |_| {
                c4.fetch_add(1, Ordering::SeqCst);
            }),
        );
        assert_eq!(reg.snapshot("eTick.").len(), 1, "re-register rebuilds list");
        assert!(reg.unregister(id_re));
    }
}