Skip to main content

des_sim/execution/phase/
event.rs

1//! The `event` module defines the `EventPhase` struct, which manages the execution
2//! of events within a micro-step.
3//!
4//! It provides mechanisms for processing events, taking them from the queue,
5//! and interacting with the simulation model and hooks.
6
7use crate::context::{EventContext, UserContext};
8use crate::execution::phase::MicroStepHandler;
9use crate::modeling::event::Event;
10use crate::modeling::hook::Hook;
11use crate::modeling::model::Model;
12use std::collections::VecDeque;
13
14/// Manages the event execution phase in the simulation.
15///
16/// This structure holds the queue of events to be processed in the current micro-step,
17/// manages the execution of event handling by the model, handles event discarding,
18/// and performs phase-end procedures.
19pub struct EventPhase<E, M: Model<E>> {
20    context: EventContext<E, M>,
21    ready_events: VecDeque<Event<E>>,
22}
23
24impl<E, M: Model<E>> EventPhase<E, M> {
25    /// Creates a new event phase.
26    pub(crate) fn new(context: EventContext<E, M>, ready_events: VecDeque<Event<E>>) -> Self {
27        EventPhase {
28            context,
29            ready_events,
30        }
31    }
32
33    /// Returns a mutable reference to the event context used in the current phase.
34    pub fn get_context(&mut self) -> &mut EventContext<E, M> {
35        &mut self.context
36    }
37
38    /// Completes the event phase and transitions to the next micro-step handler.
39    ///
40    /// This invokes the `after_event_phase` hook to update the simulation state.
41    pub fn complete_event_phase(self, model: &M) -> MicroStepHandler<EventContext<E, M>> {
42        self.context.hook().after_event_phase(
43            model,
44            self.context.current_tick(),
45            self.context.current_micro_step(),
46        );
47
48        MicroStepHandler::new(self.context)
49    }
50
51    /// Pops one event from the front of the queue.
52    pub fn take_one(&mut self) -> Option<Event<E>> {
53        self.ready_events.pop_front()
54    }
55
56    /// Searches for and pops the first event in the queue that satisfies the given predicate.
57    pub fn take_one_if<F>(&mut self, predicate: F) -> Option<Event<E>>
58    where
59        F: FnOnce(&Event<E>) -> bool,
60    {
61        // Note: VecDeque::pop_front_if is nightly. If using stable,
62        // a custom implementation or drain_filter equivalent may be needed.
63        self.ready_events.pop_front_if(|e| predicate(e))
64    }
65
66    /// Pops an event from the front of the queue only if it satisfies the given predicate.
67    pub fn take_front_if<F>(&mut self, predicate: F) -> Option<Event<E>>
68    where
69        F: FnOnce(&Event<E>) -> bool,
70    {
71        if self.ready_events.front().is_some_and(predicate) {
72            self.ready_events.pop_front()
73        } else {
74            None
75        }
76    }
77
78    /// Takes all events currently in the queue.
79    pub fn take_all(&mut self) -> VecDeque<Event<E>> {
80        std::mem::take(&mut self.ready_events)
81    }
82
83    /// Extracts and returns all events from the queue that satisfy the given predicate.
84    ///
85    /// Events that do not satisfy the predicate remain in the queue.
86    pub fn take_all_if<F>(&mut self, predicate: F) -> VecDeque<Event<E>>
87    where
88        F: FnMut(&Event<E>) -> bool,
89    {
90        let all_events = std::mem::take(&mut self.ready_events);
91
92        let (taken, remaining): (VecDeque<_>, VecDeque<_>) =
93            all_events.into_iter().partition(predicate);
94
95        self.ready_events = remaining;
96
97        taken
98    }
99
100    /// Processes the specified event using the model.
101    ///
102    /// This invokes the `before_event` and `after_event` hooks surrounding the event processing.
103    pub fn handle_event(&mut self, model: &mut M, event: Event<E>) {
104        self.context.hook().before_event(
105            model,
106            self.context.current_tick(),
107            self.context.current_micro_step(),
108            &event,
109        );
110        model.handle_event(self.get_context(), &event);
111        self.context.hook().after_event(
112            model,
113            self.context.current_tick(),
114            self.context.current_micro_step(),
115            &event,
116        );
117    }
118
119    /// Discards the specified event.
120    ///
121    /// This invokes the `discard_event` hook during the discard process.
122    pub fn discard(&mut self, model: &M, event: Event<E>) {
123        self.context.hook().discard_event(
124            model,
125            self.context.current_tick(),
126            self.context.current_micro_step(),
127            &event,
128        );
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135    use crate::context::{EventContext, UserContext};
136    use crate::event_scheduler::EventScheduler;
137    use crate::modeling::event::{Event, EventPriority};
138    use crate::modeling::hook::instance::{HookDelegate, SharedHook};
139    use crate::modeling::model::Model;
140    use crate::primitive::id::EventId;
141    use crate::primitive::time::{Duration, MicroStep, MicroStepStatus, SimTime, TickStatus};
142    use crate::source_handler::{SourceHandler, SourceReadyEntry, SourceView};
143    use std::collections::VecDeque;
144    use std::rc::Rc;
145    use std::sync::Mutex;
146
147    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
148    enum TestEvent {
149        A,
150        B,
151        C,
152    }
153
154    struct TestModel {
155        handled_events: Vec<TestEvent>,
156    }
157
158    impl Model<TestEvent> for TestModel {
159        fn handle_event(
160            &mut self,
161            _context: &mut EventContext<TestEvent, Self>,
162            event: &Event<TestEvent>,
163        ) {
164            self.handled_events.push(event.payload);
165        }
166    }
167
168    /// A hook implementation that tracks discarded events.
169    struct DiscardHook {
170        discarded_events: Rc<Mutex<Vec<TestEvent>>>,
171    }
172
173    impl Hook<TestEvent, TestModel> for DiscardHook {
174        fn before_simulation(&self, _model: &TestModel) {
175            // none
176        }
177
178        fn after_simulation(&self, _model: &TestModel, _end_tick: SimTime) {
179            // none
180        }
181
182        fn before_tick(
183            &self,
184            _model: &TestModel,
185            _current_tick: SimTime,
186            _skipped_duration: Duration,
187        ) {
188            // none
189        }
190
191        fn after_tick(
192            &self,
193            _model: &TestModel,
194            _current_tick: SimTime,
195            _last_micro_step: MicroStep,
196        ) {
197            // none
198        }
199
200        fn before_micro_step(
201            &self,
202            _model: &TestModel,
203            _current_tick: SimTime,
204            _current_micro_step: MicroStep,
205        ) {
206            // none
207        }
208
209        fn after_micro_step(
210            &self,
211            _model: &TestModel,
212            _current_tick: SimTime,
213            _current_micro_step: MicroStep,
214        ) {
215            // none
216        }
217
218        fn on_discard_remain_micro_step(
219            &self,
220            _model: &TestModel,
221            _current_tick: SimTime,
222            _first_discarded_micro_step: MicroStep,
223            _discarded_sources: &[SourceReadyEntry],
224            _discarded_events: &[Event<TestEvent>],
225        ) {
226            // none
227        }
228
229        fn before_register_source(&self, _model: &TestModel, _name: &str) {
230            // none
231        }
232
233        fn after_register_source(&self, _model: &TestModel, _name: &str) {
234            // none
235        }
236
237        fn before_source_phase(
238            &self,
239            _model: &TestModel,
240            _current_tick: SimTime,
241            _current_micro_step: MicroStep,
242        ) {
243            // none
244        }
245
246        fn before_source(
247            &self,
248            _model: &TestModel,
249            _current_tick: SimTime,
250            _current_micro_step: MicroStep,
251            _source_view: &SourceView,
252        ) {
253            // none
254        }
255
256        fn after_source(
257            &self,
258            _model: &TestModel,
259            _current_tick: SimTime,
260            _current_micro_step: MicroStep,
261            _source_view: &SourceView,
262            _computed_next_fire: Option<SimTime>,
263        ) {
264            // none
265        }
266
267        fn cancel_source(
268            &self,
269            _model: &TestModel,
270            _current_tick: SimTime,
271            _current_micro_step: MicroStep,
272            _scheduled_at: SimTime,
273            _source_view: &SourceView,
274        ) {
275            // none
276        }
277
278        fn discard_source(
279            &self,
280            _model: &TestModel,
281            _current_tick: SimTime,
282            _current_micro_step: MicroStep,
283            _source_view: &SourceView,
284        ) {
285            // none
286        }
287
288        fn after_source_phase(
289            &self,
290            _model: &TestModel,
291            _current_tick: SimTime,
292            _current_micro_step: MicroStep,
293        ) {
294            // none
295        }
296
297        fn before_event_phase(
298            &self,
299            _model: &TestModel,
300            _current_tick: SimTime,
301            _current_micro_step: MicroStep,
302        ) {
303            // none
304        }
305
306        fn before_event(
307            &self,
308            _model: &TestModel,
309            _current_tick: SimTime,
310            _current_micro_step: MicroStep,
311            _event: &Event<TestEvent>,
312        ) {
313            // none
314        }
315
316        fn after_event(
317            &self,
318            _model: &TestModel,
319            _current_tick: SimTime,
320            _current_micro_step: MicroStep,
321            _event: &Event<TestEvent>,
322        ) {
323            // none
324        }
325
326        fn cancel_event(
327            &self,
328            _model: &TestModel,
329            _current_tick: SimTime,
330            _current_micro_step: MicroStep,
331            _scheduled_at: SimTime,
332            _event: &Event<TestEvent>,
333        ) {
334            // none
335        }
336
337        fn discard_event(
338            &self,
339            _model: &TestModel,
340            _current_tick: SimTime,
341            _current_micro_step: MicroStep,
342            event: &Event<TestEvent>,
343        ) {
344            self.discarded_events.lock().unwrap().push(event.payload);
345        }
346
347        fn after_event_phase(
348            &self,
349            _model: &TestModel,
350            _current_tick: SimTime,
351            _current_micro_step: MicroStep,
352        ) {
353            // none
354        }
355    }
356
357    /// Sets up the initial state for an event phase test.
358    fn setup_event_phase() -> (EventPhase<TestEvent, TestModel>, TestModel) {
359        let model = TestModel {
360            handled_events: Vec::new(),
361        };
362        let event_context = EventContext {
363            current_tick_status: TickStatus::initialize(),
364            current_micro_step_status: MicroStepStatus::initialize(),
365            hook_delegate: HookDelegate::new(),
366            source_handler: SourceHandler::new(),
367            event_scheduler: EventScheduler::new(),
368        };
369
370        let mut ready_events = VecDeque::new();
371        ready_events.push_back(Event::new(
372            EventId::new(0),
373            EventPriority::minimum(),
374            TestEvent::A,
375        ));
376        ready_events.push_back(Event::new(
377            EventId::new(1),
378            EventPriority::minimum(),
379            TestEvent::B,
380        ));
381        ready_events.push_back(Event::new(
382            EventId::new(2),
383            EventPriority::minimum(),
384            TestEvent::C,
385        ));
386
387        (EventPhase::new(event_context, ready_events), model)
388    }
389
390    #[test]
391    fn test_new() {
392        let (event_phase, _) = setup_event_phase();
393        assert_eq!(event_phase.ready_events.len(), 3);
394    }
395
396    #[test]
397    fn test_get_context() {
398        let (mut event_phase, _) = setup_event_phase();
399        let context = event_phase.get_context();
400        assert_eq!(context.current_tick(), SimTime::zero());
401    }
402
403    #[test]
404    fn test_take_one() {
405        let (mut event_phase, _) = setup_event_phase();
406        let event = event_phase.take_one().unwrap();
407        assert_eq!(event.payload, TestEvent::A);
408        assert_eq!(event_phase.ready_events.len(), 2);
409    }
410
411    #[test]
412    fn test_take_one_if() {
413        // Test successful predicate match
414        let (mut event_phase_a, _) = setup_event_phase();
415        let event_a = event_phase_a
416            .take_one_if(|e| e.payload == TestEvent::A)
417            .unwrap();
418        assert_eq!(event_a.payload, TestEvent::A);
419        assert_eq!(event_phase_a.ready_events.len(), 2);
420        assert_eq!(
421            event_phase_a.ready_events.front().unwrap().payload,
422            TestEvent::B
423        );
424
425        // Test failed predicate match
426        let (mut event_phase_b, _) = setup_event_phase();
427        let event_b = event_phase_b.take_one_if(|_| false);
428        assert!(event_b.is_none());
429        assert_eq!(event_phase_b.ready_events.len(), 3);
430    }
431
432    #[test]
433    fn test_take_front_if() {
434        let (mut event_phase, _) = setup_event_phase();
435        let event_a = event_phase
436            .take_front_if(|e| e.payload == TestEvent::A)
437            .unwrap();
438        assert_eq!(event_a.payload, TestEvent::A);
439        assert_eq!(event_phase.ready_events.len(), 2);
440
441        let event_b = event_phase.take_front_if(|e| e.payload == TestEvent::A);
442        assert!(event_b.is_none());
443        assert_eq!(event_phase.ready_events.len(), 2);
444    }
445
446    #[test]
447    fn test_take_all() {
448        let (mut event_phase, _) = setup_event_phase();
449        let all_events = event_phase.take_all();
450        assert_eq!(all_events.len(), 3);
451        assert_eq!(event_phase.ready_events.len(), 0);
452    }
453
454    #[test]
455    fn test_take_all_if() {
456        let (mut event_phase, _) = setup_event_phase();
457        event_phase.ready_events.push_back(Event::new(
458            EventId::new(3),
459            EventPriority::minimum(),
460            TestEvent::A,
461        ));
462
463        let taken_events = event_phase.take_all_if(|e| e.payload == TestEvent::A);
464        assert_eq!(taken_events.len(), 2); // Original A + added A
465        assert_eq!(taken_events.front().unwrap().payload, TestEvent::A);
466        assert_eq!(taken_events.get(1).unwrap().payload, TestEvent::A);
467
468        assert_eq!(event_phase.ready_events.len(), 2);
469        assert_eq!(
470            event_phase.ready_events.front().unwrap().payload,
471            TestEvent::B
472        );
473        assert_eq!(
474            event_phase.ready_events.get(1).unwrap().payload,
475            TestEvent::C
476        );
477    }
478
479    #[test]
480    fn test_handle_event() {
481        let (mut event_phase, mut model) = setup_event_phase();
482        let event = Event::new(EventId::new(3), EventPriority::minimum(), TestEvent::A);
483        event_phase.handle_event(&mut model, event);
484        assert_eq!(model.handled_events.len(), 1);
485        assert_eq!(model.handled_events[0], TestEvent::A);
486    }
487
488    #[test]
489    fn test_discard() {
490        let (mut event_phase, model) = setup_event_phase();
491        let hook = SharedHook::new(DiscardHook {
492            discarded_events: Rc::new(Mutex::new(Vec::new())),
493        });
494        event_phase
495            .get_context()
496            .hook_delegate
497            .add_shared_hook(hook.clone());
498
499        let event = Event::new(EventId::new(3), EventPriority::minimum(), TestEvent::A);
500        event_phase.discard(&model, event);
501        assert_eq!(hook.get_ref().discarded_events.lock().unwrap().len(), 1);
502        assert_eq!(
503            hook.get_ref().discarded_events.lock().unwrap()[0],
504            TestEvent::A
505        );
506    }
507
508    #[test]
509    fn test_complete_event_phase() {
510        let (event_phase, model) = setup_event_phase();
511        let micro_step_handler = event_phase.complete_event_phase(&model);
512        assert_eq!(
513            micro_step_handler.ref_context().current_tick(),
514            SimTime::zero()
515        );
516    }
517}