Skip to main content

libpetri_debug/
debug_aware_event_store.rs

1//! Event store wrapper that delegates to both a primary store and a debug store.
2
3use std::sync::Arc;
4
5use libpetri_event::event_store::EventStore;
6use libpetri_event::net_event::NetEvent;
7
8use crate::debug_event_store::DebugEventStore;
9
10/// An `EventStore` that delegates to both a primary `E: EventStore` (owned)
11/// and a shared `Arc<DebugEventStore>` for the debug protocol.
12///
13/// The primary store is accessed via `&mut self` (normal `EventStore` contract).
14/// The debug store uses interior mutability (Mutex) so it can be shared with
15/// the protocol handler.
16pub struct DebugAwareEventStore<E: EventStore> {
17    primary: E,
18    debug_store: Arc<DebugEventStore>,
19}
20
21impl<E: EventStore> DebugAwareEventStore<E> {
22    /// Creates a new `DebugAwareEventStore`.
23    pub fn new(primary: E, debug_store: Arc<DebugEventStore>) -> Self {
24        Self {
25            primary,
26            debug_store,
27        }
28    }
29
30    /// Returns a reference to the primary event store.
31    pub fn primary(&self) -> &E {
32        &self.primary
33    }
34
35    /// Returns a mutable reference to the primary event store.
36    pub fn primary_mut(&mut self) -> &mut E {
37        &mut self.primary
38    }
39
40    /// Returns a clone of the `Arc<DebugEventStore>`.
41    pub fn debug_store(&self) -> Arc<DebugEventStore> {
42        Arc::clone(&self.debug_store)
43    }
44}
45
46impl<E: EventStore> EventStore for DebugAwareEventStore<E> {
47    const ENABLED: bool = true;
48
49    fn append(&mut self, event: NetEvent) {
50        // Always forward to debug store (swallow failures)
51        self.debug_store.append(event.clone());
52        // Forward to primary if enabled
53        if E::ENABLED {
54            self.primary.append(event);
55        }
56    }
57
58    fn events(&self) -> &[NetEvent] {
59        if E::ENABLED {
60            self.primary.events()
61        } else {
62            &[]
63        }
64    }
65
66    fn size(&self) -> usize {
67        if E::ENABLED { self.primary.size() } else { 0 }
68    }
69
70    fn is_empty(&self) -> bool {
71        if E::ENABLED {
72            self.primary.is_empty()
73        } else {
74            true
75        }
76    }
77}
78
79impl<E: EventStore> Default for DebugAwareEventStore<E> {
80    fn default() -> Self {
81        Self {
82            primary: E::default(),
83            debug_store: Arc::new(DebugEventStore::new("default".into())),
84        }
85    }
86}
87
88impl<E: EventStore> std::fmt::Debug for DebugAwareEventStore<E>
89where
90    E: std::fmt::Debug,
91{
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        f.debug_struct("DebugAwareEventStore")
94            .field("primary", &self.primary)
95            .field("debug_store", &self.debug_store)
96            .finish()
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use libpetri_event::event_store::{InMemoryEventStore, NoopEventStore};
104    use std::sync::Arc as StdArc;
105
106    fn exec_started(ts: u64) -> NetEvent {
107        NetEvent::ExecutionStarted {
108            net_name: StdArc::from("test"),
109            timestamp: ts,
110        }
111    }
112
113    #[test]
114    fn delegates_to_both_stores() {
115        let debug_store = Arc::new(DebugEventStore::new("s1".into()));
116        let mut store =
117            DebugAwareEventStore::new(InMemoryEventStore::new(), Arc::clone(&debug_store));
118
119        store.append(exec_started(100));
120
121        assert_eq!(store.size(), 1);
122        assert_eq!(store.events().len(), 1);
123        assert_eq!(debug_store.size(), 1);
124    }
125
126    #[test]
127    fn delegates_to_debug_even_with_noop_primary() {
128        let debug_store = Arc::new(DebugEventStore::new("s1".into()));
129        let mut store = DebugAwareEventStore::new(NoopEventStore, Arc::clone(&debug_store));
130
131        store.append(exec_started(100));
132
133        // Primary is noop, so size/events return empty
134        assert_eq!(store.size(), 0);
135        assert!(store.is_empty());
136        // But debug store got the event
137        assert_eq!(debug_store.size(), 1);
138    }
139
140    #[test]
141    fn enabled_is_always_true() {
142        assert!(DebugAwareEventStore::<NoopEventStore>::ENABLED);
143        assert!(DebugAwareEventStore::<InMemoryEventStore>::ENABLED);
144    }
145
146    #[test]
147    fn debug_store_accessible() {
148        let debug_store = Arc::new(DebugEventStore::new("s1".into()));
149        let store = DebugAwareEventStore::new(InMemoryEventStore::new(), Arc::clone(&debug_store));
150        assert_eq!(store.debug_store().session_id(), "s1");
151    }
152}