1use crate::context::UserContext;
7use crate::event_scheduler::EventScheduler;
8use crate::modeling::event::{Event, EventPriority};
9use crate::modeling::hook::Hook;
10use crate::modeling::hook::instance::HookDelegate;
11use crate::modeling::model::Model;
12use crate::modeling::source::Source;
13use crate::primitive::time::{Duration, MicroStep, MicroStepStatus, SimTime, TickStatus};
14use crate::source_handler::{SourceHandler, SourceReadyEntry, SourceView};
15
16pub struct EventContext<E, M: Model<E>> {
21 pub(crate) current_tick_status: TickStatus,
22 pub(crate) current_micro_step_status: MicroStepStatus,
23 pub(crate) hook_delegate: HookDelegate<E, M>,
24 pub(crate) source_handler: SourceHandler<E, M>,
25 pub(crate) event_scheduler: EventScheduler<E>,
26}
27
28impl<E, M: Model<E>> UserContext<E, M> for EventContext<E, M> {
29 fn current_tick(&self) -> SimTime {
30 self.current_tick_status.current()
31 }
32
33 fn current_micro_step(&self) -> MicroStep {
34 self.current_micro_step_status.current()
35 }
36
37 fn schedule_event(&mut self, delay: Duration, priority: EventPriority, event_payload: E) {
38 self.event_scheduler
39 .schedule(self.current_tick(), delay, priority, event_payload);
40 }
41}
42
43impl<E, M: Model<E>> EventContext<E, M> {
44 pub(crate) fn hook(&self) -> &impl Hook<E, M> {
46 &self.hook_delegate
47 }
48
49 pub fn add_source<S>(&mut self, model: &M, name: &'static str, mut source: S)
56 where
57 S: Source<E, M> + 'static,
58 {
59 self.hook().before_register_source(model, name);
60 let first_fire_delay = source.on_registered(self, model);
61 self.source_handler.add_source_after_registered_action(
62 name,
63 self.current_tick(),
64 first_fire_delay,
65 source,
66 );
67 self.hook().after_register_source(model, name);
68 }
69
70 pub fn cancel_scheduled_sources<S, F>(
79 &mut self,
80 model: &M,
81 pred: F,
82 ) -> Vec<(SimTime, SourceReadyEntry)>
83 where
84 S: Source<E, M> + 'static,
85 F: FnMut(SimTime, &SourceReadyEntry) -> bool,
86 {
87 let mut result = Vec::new();
88 let now = self.current_tick();
89 let micro_step = self.current_micro_step();
90 let canceled = self.source_handler.drain_cancel_scheduled(pred);
91
92 canceled.into_iter().for_each(|(scheduled_at, entry)| {
93 self.hook().cancel_source(
94 model,
95 now,
96 micro_step,
97 scheduled_at,
98 &SourceView::new(entry.source_id(), entry.clone_name_arc()),
99 );
100 result.push((scheduled_at, entry));
101 });
102
103 result
104 }
105
106 pub fn cancel_scheduled_events<F>(&mut self, model: &M, pred: F) -> Vec<(SimTime, Event<E>)>
115 where
116 F: FnMut(SimTime, &Event<E>) -> bool,
117 {
118 let mut result = Vec::new();
119 let now = self.current_tick();
120 let micro_step = self.current_micro_step();
121 let canceled = self.event_scheduler.drain_cancel_scheduled(pred);
122
123 canceled.into_iter().for_each(|(scheduled_at, event)| {
124 self.hook()
125 .cancel_event(model, now, micro_step, scheduled_at, &event);
126 result.push((scheduled_at, event));
127 });
128
129 result
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use crate::context::SourceContext;
137 use crate::modeling::hook::instance::SharedHook;
138 use std::cell::RefCell;
139 use std::fmt::Debug;
140 use std::rc::Rc;
141
142 #[derive(Debug, Clone, PartialEq)]
144 struct TestEvent;
145
146 struct TestModel;
148
149 impl Model<TestEvent> for TestModel {
150 fn handle_event(
151 &mut self,
152 _event_context: &mut EventContext<TestEvent, Self>,
153 _event: &Event<TestEvent>,
154 ) {
155 }
157 }
158
159 struct TestSource {
161 initial_delay: Duration,
162 }
163
164 impl Source<TestEvent, TestModel> for TestSource {
165 fn on_registered(
166 &mut self,
167 context: &mut dyn UserContext<TestEvent, TestModel>,
168 _model: &TestModel,
169 ) -> Option<Duration> {
170 context.schedule_event(Duration::ticks(5), EventPriority::minimum(), TestEvent);
171 Some(self.initial_delay)
172 }
173
174 fn fire(
175 &mut self,
176 context: &mut SourceContext<TestEvent, TestModel>,
177 _model: &TestModel,
178 ) -> Option<Duration> {
179 context.schedule_event(Duration::ticks(5), EventPriority::minimum(), TestEvent);
180 Some(Duration::ticks(5))
181 }
182 }
183
184 #[derive(Default)]
188 struct MockHook {
189 before_register_source_called: Rc<RefCell<Vec<String>>>,
190 after_register_source_called: Rc<RefCell<Vec<String>>>,
191 cancel_source_called: Rc<RefCell<Vec<String>>>,
192 cancel_event_called: Rc<RefCell<Vec<String>>>,
193 }
194
195 impl MockHook {
196 fn new() -> Self {
198 Default::default()
199 }
200 }
201
202 impl<E: Debug, M: Model<E>> Hook<E, M> for MockHook {
203 fn before_simulation(&self, _model: &M) {
204 unreachable!();
205 }
206 fn after_simulation(&self, _model: &M, _end_tick: SimTime) {
207 unreachable!();
208 }
209 fn before_tick(&self, _model: &M, _current_tick: SimTime, _skipped_duration: Duration) {
210 unreachable!();
211 }
212 fn after_tick(&self, _model: &M, _current_tick: SimTime, _last_micro_step: MicroStep) {
213 unreachable!();
214 }
215 fn before_micro_step(
216 &self,
217 _model: &M,
218 _current_tick: SimTime,
219 _current_micro_step: MicroStep,
220 ) {
221 unreachable!();
222 }
223 fn after_micro_step(
224 &self,
225 _model: &M,
226 _current_tick: SimTime,
227 _current_micro_step: MicroStep,
228 ) {
229 unreachable!();
230 }
231 fn on_discard_remain_micro_step(
232 &self,
233 _model: &M,
234 _current_tick: SimTime,
235 _first_discarded_micro_step: MicroStep,
236 _discarded_sources: &[SourceReadyEntry],
237 _discarded_events: &[Event<E>],
238 ) {
239 unreachable!();
240 }
241
242 fn before_register_source(&self, _model: &M, name: &str) {
243 self.before_register_source_called
244 .borrow_mut()
245 .push(name.to_string());
246 }
247
248 fn after_register_source(&self, _model: &M, name: &str) {
249 self.after_register_source_called
250 .borrow_mut()
251 .push(name.to_string());
252 }
253
254 fn before_source_phase(
255 &self,
256 _model: &M,
257 _current_tick: SimTime,
258 _current_micro_step: MicroStep,
259 ) {
260 unreachable!();
261 }
262
263 fn before_source(
264 &self,
265 _model: &M,
266 _current_tick: SimTime,
267 _current_micro_step: MicroStep,
268 _source_view: &SourceView,
269 ) {
270 unreachable!();
271 }
272 fn after_source(
273 &self,
274 _model: &M,
275 _current_tick: SimTime,
276 _current_micro_step: MicroStep,
277 _source_view: &SourceView,
278 _computed_next_fire: Option<SimTime>,
279 ) {
280 unreachable!();
281 }
282
283 fn cancel_source(
284 &self,
285 _model: &M,
286 _now: SimTime,
287 _micro_step: MicroStep,
288 _scheduled_at: SimTime,
289 source_view: &SourceView,
290 ) {
291 self.cancel_source_called
292 .borrow_mut()
293 .push(source_view.name().to_string());
294 }
295
296 fn discard_source(
297 &self,
298 _model: &M,
299 _current_tick: SimTime,
300 _current_micro_step: MicroStep,
301 _source_view: &SourceView,
302 ) {
303 unreachable!();
304 }
305
306 fn after_source_phase(
307 &self,
308 _model: &M,
309 _current_tick: SimTime,
310 _current_micro_step: MicroStep,
311 ) {
312 unreachable!();
313 }
314 fn before_event_phase(
315 &self,
316 _model: &M,
317 _current_tick: SimTime,
318 _current_micro_step: MicroStep,
319 ) {
320 unreachable!();
321 }
322 fn before_event(
323 &self,
324 _model: &M,
325 _current_tick: SimTime,
326 _current_micro_step: MicroStep,
327 _event: &Event<E>,
328 ) {
329 unreachable!();
330 }
331 fn after_event(
332 &self,
333 _model: &M,
334 _current_tick: SimTime,
335 _current_micro_step: MicroStep,
336 _event: &Event<E>,
337 ) {
338 unreachable!();
339 }
340
341 fn cancel_event(
342 &self,
343 _model: &M,
344 _now: SimTime,
345 _micro_step: MicroStep,
346 _scheduled_at: SimTime,
347 event: &Event<E>,
348 ) {
349 self.cancel_event_called
350 .borrow_mut()
351 .push(format!("{:?}", event.payload));
352 }
353
354 fn discard_event(
355 &self,
356 _model: &M,
357 _current_tick: SimTime,
358 _current_micro_step: MicroStep,
359 _event: &Event<E>,
360 ) {
361 unreachable!();
362 }
363 fn after_event_phase(
364 &self,
365 _model: &M,
366 _current_tick: SimTime,
367 _current_micro_step: MicroStep,
368 ) {
369 unreachable!();
370 }
371 }
372
373 fn setup() -> (
375 EventContext<TestEvent, TestModel>,
376 SharedHook<TestEvent, TestModel, MockHook>,
377 ) {
378 let test_hook = MockHook::new();
379 let shared_hook = SharedHook::new(test_hook);
380 let mut hook_delegate = HookDelegate::new();
381 hook_delegate.add_shared_hook(shared_hook.clone());
382
383 let context = EventContext {
384 current_tick_status: TickStatus::initialize(),
385 current_micro_step_status: MicroStepStatus::new(MicroStep::zero()),
386 hook_delegate,
387 source_handler: SourceHandler::new(),
388 event_scheduler: EventScheduler::new(),
389 };
390
391 (context, shared_hook)
392 }
393
394 #[test]
395 fn test_current_tick() {
396 let (context, _) = setup();
397 assert_eq!(context.current_tick(), SimTime::from_ticks(0));
398 }
399
400 #[test]
401 fn test_current_micro_step() {
402 let (context, _) = setup();
403 assert_eq!(context.current_micro_step(), MicroStep::zero());
404 }
405
406 #[test]
407 fn test_add_source_after() {
408 let model = TestModel;
409 let (mut context, shared_hook) = setup();
410 let initial_sources_count = context.source_handler.ready_queue_len();
411 let delay = Duration::ticks(10);
412
413 context.add_source(
414 &model,
415 "test_source",
416 TestSource {
417 initial_delay: delay,
418 },
419 );
420
421 context.source_handler.flush_pending();
422 context.event_scheduler.flush_pending(); assert_eq!(
425 context.source_handler.ready_queue_len(),
426 initial_sources_count + 1
427 );
428
429 let (scheduled_at, scheduled_source) = context.source_handler.peek().unwrap();
430 assert_eq!(scheduled_at, SimTime::from_ticks(0) + delay);
431 assert_eq!(scheduled_source.source_id.value(), 0); assert_eq!(
434 shared_hook
435 .get_ref()
436 .before_register_source_called
437 .borrow()
438 .len(),
439 1
440 );
441 assert_eq!(
442 shared_hook.get_ref().before_register_source_called.borrow()[0],
443 "test_source"
444 );
445 assert_eq!(
446 shared_hook
447 .get_ref()
448 .after_register_source_called
449 .borrow()
450 .len(),
451 1
452 );
453 assert_eq!(
454 shared_hook.get_ref().after_register_source_called.borrow()[0],
455 "test_source"
456 );
457 }
458
459 #[test]
460 fn test_add_source_at_now() {
461 let model = TestModel;
462 let (mut context, shared_hook) = setup();
463 let initial_sources_count = context.source_handler.ready_queue_len();
464
465 context.add_source(
466 &model,
467 "test_source_now",
468 TestSource {
469 initial_delay: Duration::zero(),
470 },
471 );
472
473 context.source_handler.flush_pending();
474 context.event_scheduler.flush_pending(); assert_eq!(
477 context.source_handler.ready_queue_len(),
478 initial_sources_count + 1
479 );
480
481 let (scheduled_at, scheduled_source) = context.source_handler.peek().unwrap();
482 assert_eq!(scheduled_at, SimTime::from_ticks(0));
483 assert_eq!(scheduled_source.source_id.value(), 0); assert_eq!(
486 shared_hook
487 .get_ref()
488 .before_register_source_called
489 .borrow()
490 .len(),
491 1
492 );
493 assert_eq!(
494 shared_hook.get_ref().before_register_source_called.borrow()[0],
495 "test_source_now"
496 );
497 assert_eq!(
498 shared_hook
499 .get_ref()
500 .after_register_source_called
501 .borrow()
502 .len(),
503 1
504 );
505 assert_eq!(
506 shared_hook.get_ref().after_register_source_called.borrow()[0],
507 "test_source_now"
508 );
509 }
510
511 #[test]
512 fn test_schedule_event() {
513 let (mut context, _) = setup();
514
515 context.event_scheduler.schedule(
517 SimTime::from_ticks(0),
518 Duration::one(),
519 EventPriority::minimum(),
520 TestEvent,
521 );
522 context.event_scheduler.schedule(
523 SimTime::from_ticks(0),
524 Duration::one(),
525 EventPriority::minimum(),
526 TestEvent,
527 );
528 context.event_scheduler.schedule(
529 SimTime::from_ticks(0),
530 Duration::one(),
531 EventPriority::minimum(),
532 TestEvent,
533 );
534 context.event_scheduler.flush_pending();
535
536 let initial_scheduled_events_count = context.event_scheduler.ready_queue_len();
537 let delay = Duration::ticks(5);
538 let priority = EventPriority::new(10);
539 let event_payload = TestEvent;
540
541 context.schedule_event(delay, priority, event_payload.clone());
542 context.source_handler.flush_pending(); context.event_scheduler.flush_pending();
544
545 assert_eq!(
546 context.event_scheduler.ready_queue_len(),
547 initial_scheduled_events_count + 1
548 );
549
550 let (scheduled_at, event) = context.event_scheduler.peek().unwrap();
551 assert_eq!(scheduled_at, SimTime::from_ticks(1));
552 assert_eq!(event.priority, EventPriority::minimum());
553 assert_eq!(event.payload, TestEvent);
554 }
555
556 #[test]
557 fn test_cancel_scheduled_events() {
558 let (mut context, shared_hook) = setup();
559 let model = TestModel;
560
561 context.schedule_event(Duration::ticks(5), EventPriority::minimum(), TestEvent);
562 context.schedule_event(Duration::ticks(10), EventPriority::minimum(), TestEvent);
563 context.source_handler.flush_pending();
564 context.event_scheduler.flush_pending();
565
566 let canceled_events = context.cancel_scheduled_events(&model, |_, _| true);
567 assert_eq!(canceled_events.len(), 2);
568 assert_eq!(context.event_scheduler.ready_queue_len(), 0);
569 assert_eq!(shared_hook.get_ref().cancel_event_called.borrow().len(), 2);
570 assert_eq!(
571 shared_hook.get_ref().cancel_event_called.borrow()[0],
572 "TestEvent"
573 );
574 assert_eq!(
575 shared_hook.get_ref().cancel_event_called.borrow()[1],
576 "TestEvent"
577 );
578
579 context.schedule_event(Duration::ticks(5), EventPriority::minimum(), TestEvent);
581 context.schedule_event(Duration::ticks(10), EventPriority::minimum(), TestEvent);
582
583 context.source_handler.flush_pending();
584 context.event_scheduler.flush_pending();
585
586 let canceled_events_filtered = context
587 .cancel_scheduled_events(&model, |scheduled_at, _| {
588 scheduled_at == SimTime::from_ticks(5)
589 });
590 assert_eq!(canceled_events_filtered.len(), 1);
591 assert_eq!(canceled_events_filtered[0].0, SimTime::from_ticks(5));
592 assert_eq!(context.event_scheduler.ready_queue_len(), 1);
593 let (remaining_scheduled_at, _) = context.event_scheduler.peek().unwrap();
594 assert_eq!(remaining_scheduled_at, SimTime::from_ticks(10));
595 assert_eq!(shared_hook.get_ref().cancel_event_called.borrow().len(), 3);
596 assert_eq!(
597 shared_hook.get_ref().cancel_event_called.borrow()[2],
598 "TestEvent"
599 );
600 }
601
602 #[test]
603 fn test_cancel_scheduled_sources() {
604 let (mut context, shared_hook) = setup();
605 let model = TestModel;
606
607 context.add_source(
608 &model,
609 "source1",
610 TestSource {
611 initial_delay: Duration::ticks(5),
612 },
613 );
614 context.add_source(
615 &model,
616 "source2",
617 TestSource {
618 initial_delay: Duration::ticks(10),
619 },
620 );
621 context.source_handler.flush_pending();
622 context.event_scheduler.flush_pending();
623
624 let canceled_sources =
625 context.cancel_scheduled_sources::<TestSource, _>(&model, |_, _| true);
626 assert_eq!(canceled_sources.len(), 2);
627 assert_eq!(context.source_handler.ready_queue_len(), 0);
628 assert_eq!(shared_hook.get_ref().cancel_source_called.borrow().len(), 2);
629 assert_eq!(
630 shared_hook.get_ref().cancel_source_called.borrow()[0],
631 "source1"
632 );
633 assert_eq!(
634 shared_hook.get_ref().cancel_source_called.borrow()[1],
635 "source2"
636 );
637
638 context.add_source(
640 &model,
641 "source3",
642 TestSource {
643 initial_delay: Duration::ticks(5),
644 },
645 );
646 context.add_source(
647 &model,
648 "source4",
649 TestSource {
650 initial_delay: Duration::ticks(10),
651 },
652 );
653 context.source_handler.flush_pending();
654 context.event_scheduler.flush_pending();
655
656 let canceled_sources_filtered = context
657 .cancel_scheduled_sources::<TestSource, _>(&model, |scheduled_at, _| {
658 scheduled_at == SimTime::from_ticks(5)
659 });
660 assert_eq!(canceled_sources_filtered.len(), 1);
661 assert_eq!(canceled_sources_filtered[0].0, SimTime::from_ticks(5));
662 assert_eq!(context.source_handler.ready_queue_len(), 1);
663 let (remaining_scheduled_at, _) = context.source_handler.peek().unwrap();
664 assert_eq!(remaining_scheduled_at, SimTime::from_ticks(10));
665 assert_eq!(shared_hook.get_ref().cancel_source_called.borrow().len(), 3);
666 assert_eq!(
667 shared_hook.get_ref().cancel_source_called.borrow()[2],
668 "source3"
669 );
670 }
671}