bb_runtime/framework/event_source.rs
1//! `EventSource` - registered `event_kind โ ComponentTag`
2//! subscription table consulted by the engine's Phase 3 bus event
3//! routing per ENGINE.md ยง10.7.
4//!
5//! Syscall ops with `event_subscriptions()` declarations register
6//! themselves here at install time; the engine's `poll()` Phase 3
7//! consults `subscribers(event_kind)` to deliver each drained
8//! `NodeEvent` to the matching consumer ops.
9
10use std::collections::HashMap;
11
12use crate::ids::ComponentTag;
13
14/// `event_kind โ Vec<ComponentTag>` subscription table.
15#[derive(Default)]
16pub struct EventSource {
17 subscriptions: HashMap<String, Vec<ComponentTag>>,
18}
19
20impl EventSource {
21 /// Construct a fresh, empty registry.
22 pub fn new() -> Self {
23 Self::default()
24 }
25
26 /// Subscribe `tag` to events of `event_kind`. Idempotent -
27 /// re-subscribing the same tag is a no-op.
28 pub fn subscribe(&mut self, event_kind: &str, tag: ComponentTag) {
29 let entry = self
30 .subscriptions
31 .entry(event_kind.to_string())
32 .or_default();
33 if !entry.contains(&tag) {
34 entry.push(tag);
35 }
36 }
37
38 /// Remove `tag`'s subscription to `event_kind` if present.
39 pub fn unsubscribe(&mut self, event_kind: &str, tag: ComponentTag) {
40 if let Some(entry) = self.subscriptions.get_mut(event_kind) {
41 entry.retain(|t| *t != tag);
42 if entry.is_empty() {
43 self.subscriptions.remove(event_kind);
44 }
45 }
46 }
47
48 /// Subscribers to `event_kind`. Returns an empty slice when no
49 /// component is subscribed.
50 pub fn subscribers(&self, event_kind: &str) -> &[ComponentTag] {
51 self.subscriptions
52 .get(event_kind)
53 .map(|v| v.as_slice())
54 .unwrap_or(&[])
55 }
56
57 /// Number of distinct event kinds with at least one subscriber.
58 pub fn len(&self) -> usize {
59 self.subscriptions.len()
60 }
61
62 /// `true` when no subscriptions are registered.
63 pub fn is_empty(&self) -> bool {
64 self.subscriptions.is_empty()
65 }
66}
67