1use crate::event_scheduler::EventScheduler;
8use crate::execution::phase::MicroStepHandler;
9use crate::execution::{SimulationError, SimulationOutput, SimulationResult};
10use crate::modeling::event::Event;
11use crate::modeling::hook::Hook;
12use crate::modeling::hook::instance::HookDelegate;
13use crate::modeling::model::Model;
14use crate::primitive::time::{Duration, SimTime};
15use crate::primitive::time::{MicroStepStatus, TickStatus};
16use crate::source_handler::{SourceHandler, SourceReadyEntry};
17use std::cmp::min;
18use std::collections::VecDeque;
19
20#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
22pub enum ExecutorStatus {
23 NoMoreEvent,
25 ExistsMoreEvent,
27}
28
29pub struct ExecutorContext<E, M: Model<E>> {
35 pub(crate) next_tick_status: TickStatus,
36 pub(crate) current_tick: SimTime,
37 pub(crate) hook_delegate: HookDelegate<E, M>,
38 pub(crate) source_handler: SourceHandler<E, M>,
39 pub(crate) event_scheduler: EventScheduler<E>,
40}
41
42impl<E, M: Model<E>> ExecutorContext<E, M> {
43 pub(crate) fn hook(&self) -> &impl Hook<E, M> {
45 &self.hook_delegate
46 }
47
48 pub fn peek_next_tick(&self) -> (ExecutorStatus, TickStatus) {
53 let next_event_fired_at = self.event_scheduler.peek_next_time();
54 let executor_status = if next_event_fired_at.is_some() {
55 ExecutorStatus::ExistsMoreEvent
56 } else {
57 ExecutorStatus::NoMoreEvent
58 };
59
60 (executor_status, self.next_tick_status)
61 }
62
63 pub fn begin_tick(self, model: &M) -> ActiveExecutorContext<E, M> {
67 self.hook_delegate.before_tick(
68 model,
69 self.next_tick_status.current(),
70 self.next_tick_status.skipped(),
71 );
72
73 ActiveExecutorContext {
74 current_tick_status: self.next_tick_status,
76 next_micro_step_status: MicroStepStatus::initialize(),
77 hook_delegate: self.hook_delegate,
78 source_handler: self.source_handler,
79 event_scheduler: self.event_scheduler,
80 }
81 }
82
83 pub fn end_simulation_as_ok<Err>(self, model: M) -> SimulationResult<M, Err> {
85 self.hook().after_simulation(&model, self.current_tick);
86 Ok(SimulationOutput::new(self.current_tick, model))
87 }
88
89 pub fn end_simulation_as_error<Err>(self, model: M, error: Err) -> SimulationResult<M, Err> {
91 self.hook().after_simulation(&model, self.current_tick);
92 Err(SimulationError::new(self.current_tick, model, error))
93 }
94}
95
96pub struct ActiveExecutorContext<E, M: Model<E>> {
98 pub(crate) current_tick_status: TickStatus,
99 pub(crate) next_micro_step_status: MicroStepStatus,
101 pub(crate) hook_delegate: HookDelegate<E, M>,
102 pub(crate) source_handler: SourceHandler<E, M>,
103 pub(crate) event_scheduler: EventScheduler<E>,
104}
105
106impl<E, M: Model<E>> ActiveExecutorContext<E, M> {
107 pub(crate) fn hook(&self) -> &impl Hook<E, M> {
108 &self.hook_delegate
109 }
110
111 pub fn begin_micro_step(self, model: &M) -> MicroStepHandler<ActiveExecutorContext<E, M>> {
113 self.hook().before_micro_step(
114 model,
115 self.current_tick_status.current(),
116 self.next_micro_step_status.current(),
117 );
118
119 MicroStepHandler::new(self)
120 }
121
122 pub fn end_tick_with_increment_tick(self, model: &M) -> ExecutorContext<E, M> {
124 let current_tick = self.current_tick_status.current();
125 self.hook()
126 .after_tick(model, current_tick, self.next_micro_step_status.current());
127
128 let next_tick = current_tick + Duration::one();
129 let next_tick_status = TickStatus::new(next_tick, Duration::zero());
130
131 ExecutorContext {
132 next_tick_status,
133 current_tick,
134 hook_delegate: self.hook_delegate,
135 source_handler: self.source_handler,
136 event_scheduler: self.event_scheduler,
137 }
138 }
139
140 pub fn end_tick_with_jump_to_next_tick(self, model: &M) -> ExecutorContext<E, M> {
143 let current_tick = self.current_tick_status.current();
144 self.hook()
145 .after_tick(model, current_tick, self.next_micro_step_status.current());
146
147 let (skipped, next_tick) = match (
149 self.source_handler.peek_next_time(),
150 self.event_scheduler.peek_next_time(),
151 ) {
152 (Some(next_scheduled_at), None) | (None, Some(next_scheduled_at)) => (
153 next_scheduled_at - current_tick - Duration::one(),
154 next_scheduled_at,
155 ),
156 (Some(source_next_scheduled_at), Some(event_next_scheduled_at)) => {
157 let next_scheduled_at = min(source_next_scheduled_at, event_next_scheduled_at);
158 (
159 next_scheduled_at - current_tick - Duration::one(),
160 next_scheduled_at,
161 )
162 }
163 (_, _) => {
164 (Duration::zero(), current_tick + Duration::one())
166 }
167 };
168 let next_tick_status = TickStatus::new(next_tick, skipped);
169
170 ExecutorContext {
171 next_tick_status,
172 current_tick,
173 hook_delegate: self.hook_delegate,
174 source_handler: self.source_handler,
175 event_scheduler: self.event_scheduler,
176 }
177 }
178
179 pub fn discard_remain_micro_step(
184 &mut self,
185 model: &M,
186 ) -> (VecDeque<SourceReadyEntry>, VecDeque<Event<E>>) {
187 let current_tick = self.current_tick_status.current();
188 let mut ready_sources = self.source_handler.drain_ready(current_tick);
189 let mut ready_events = self.event_scheduler.drain_ready(current_tick);
190
191 self.hook().on_discard_remain_micro_step(
192 model,
193 current_tick,
194 self.next_micro_step_status.current(),
195 ready_sources.make_contiguous(),
196 ready_events.make_contiguous(),
197 );
198
199 (ready_sources, ready_events)
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use crate::context::{EventContext, SourceContext, UserContext};
207 use crate::modeling::event::{Event, EventPriority};
208 use crate::modeling::hook::instance::SharedHook;
209 use crate::modeling::source::Source;
210 use crate::primitive::time::{Duration, MicroStep, SimTime};
211 use crate::source_handler::SourceView;
212 use std::cell::RefCell;
213 use std::rc::Rc;
214
215 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
217 struct TestEvent;
218
219 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
221 struct TestSource {
222 tick: Duration,
223 }
224
225 impl Source<TestEvent, TestModel> for TestSource {
226 fn on_registered(
227 &mut self,
228 _context: &mut dyn UserContext<TestEvent, TestModel>,
229 _model: &TestModel,
230 ) -> Option<Duration> {
231 Some(self.tick)
232 }
233
234 fn fire(
235 &mut self,
236 _context: &mut SourceContext<TestEvent, TestModel>,
237 _model: &TestModel,
238 ) -> Option<Duration> {
239 Some(self.tick)
240 }
241 }
242
243 #[derive(Debug)]
245 struct TestModel;
246
247 impl Model<TestEvent> for TestModel {
248 fn handle_event(
249 &mut self,
250 _context: &mut EventContext<TestEvent, Self>,
251 _event: &Event<TestEvent>,
252 ) {
253 }
255 }
256
257 #[derive(Default)]
259 struct MockHook {
260 before_tick_called: Rc<RefCell<Vec<(SimTime, Duration)>>>,
261 after_tick_called: Rc<RefCell<Vec<(SimTime, MicroStep)>>>,
262 before_micro_step_called: Rc<RefCell<Vec<(SimTime, MicroStep)>>>,
263 #[allow(clippy::type_complexity)]
264 on_discard_remain_micro_step_called: Rc<RefCell<Vec<(SimTime, MicroStep, usize, usize)>>>,
265 after_simulation_called: Rc<RefCell<Vec<SimTime>>>,
266 }
267
268 impl MockHook {
269 fn new() -> Self {
270 Default::default()
271 }
272 }
273
274 impl<E, M: Model<E>> Hook<E, M> for MockHook {
275 fn before_simulation(&self, _model: &M) {
276 unreachable!();
277 }
278
279 fn after_simulation(&self, _model: &M, last_tick: SimTime) {
280 self.after_simulation_called.borrow_mut().push(last_tick);
281 }
282
283 fn before_tick(&self, _model: &M, now: SimTime, skipped: Duration) {
284 self.before_tick_called.borrow_mut().push((now, skipped));
285 }
286
287 fn after_tick(&self, _model: &M, now: SimTime, micro_step: MicroStep) {
288 self.after_tick_called.borrow_mut().push((now, micro_step));
289 }
290
291 fn before_micro_step(&self, _model: &M, now: SimTime, micro_step: MicroStep) {
292 self.before_micro_step_called
293 .borrow_mut()
294 .push((now, micro_step));
295 }
296
297 fn after_micro_step(
298 &self,
299 _model: &M,
300 _current_tick: SimTime,
301 _current_micro_step: MicroStep,
302 ) {
303 unreachable!();
304 }
305
306 fn on_discard_remain_micro_step(
307 &self,
308 _model: &M,
309 now: SimTime,
310 micro_step: MicroStep,
311 ready_sources: &[SourceReadyEntry],
312 ready_events: &[Event<E>],
313 ) {
314 self.on_discard_remain_micro_step_called.borrow_mut().push((
315 now,
316 micro_step,
317 ready_sources.len(),
318 ready_events.len(),
319 ));
320 }
321
322 fn before_register_source(&self, _model: &M, _name: &str) {
323 unreachable!();
324 }
325
326 fn after_register_source(&self, _model: &M, _name: &str) {
327 unreachable!();
328 }
329
330 fn before_source_phase(
331 &self,
332 _model: &M,
333 _current_tick: SimTime,
334 _current_micro_step: MicroStep,
335 ) {
336 unreachable!();
337 }
338
339 fn before_source(
340 &self,
341 _model: &M,
342 _current_tick: SimTime,
343 _current_micro_step: MicroStep,
344 _source_view: &SourceView,
345 ) {
346 unreachable!();
347 }
348
349 fn after_source(
350 &self,
351 _model: &M,
352 _current_tick: SimTime,
353 _current_micro_step: MicroStep,
354 _source_view: &SourceView,
355 _computed_next_fire: Option<SimTime>,
356 ) {
357 unreachable!();
358 }
359
360 fn cancel_source(
361 &self,
362 _model: &M,
363 _current_tick: SimTime,
364 _current_micro_step: MicroStep,
365 _scheduled_at: SimTime,
366 _source_view: &SourceView,
367 ) {
368 unreachable!();
369 }
370
371 fn discard_source(
372 &self,
373 _model: &M,
374 _current_tick: SimTime,
375 _current_micro_step: MicroStep,
376 _source_view: &SourceView,
377 ) {
378 unreachable!();
379 }
380
381 fn after_source_phase(
382 &self,
383 _model: &M,
384 _current_tick: SimTime,
385 _current_micro_step: MicroStep,
386 ) {
387 unreachable!();
388 }
389
390 fn before_event_phase(
391 &self,
392 _model: &M,
393 _current_tick: SimTime,
394 _current_micro_step: MicroStep,
395 ) {
396 unreachable!();
397 }
398
399 fn before_event(
400 &self,
401 _model: &M,
402 _current_tick: SimTime,
403 _current_micro_step: MicroStep,
404 _event: &Event<E>,
405 ) {
406 unreachable!();
408 }
409
410 fn after_event(
411 &self,
412 _model: &M,
413 _current_tick: SimTime,
414 _current_micro_step: MicroStep,
415 _event: &Event<E>,
416 ) {
417 unreachable!();
419 }
420
421 fn cancel_event(
422 &self,
423 _model: &M,
424 _current_tick: SimTime,
425 _current_micro_step: MicroStep,
426 _scheduled_at: SimTime,
427 _event: &Event<E>,
428 ) {
429 unreachable!();
431 }
432
433 fn discard_event(
434 &self,
435 _model: &M,
436 _current_tick: SimTime,
437 _current_micro_step: MicroStep,
438 _event: &Event<E>,
439 ) {
440 unreachable!();
442 }
443
444 fn after_event_phase(
445 &self,
446 _model: &M,
447 _current_tick: SimTime,
448 _current_micro_step: MicroStep,
449 ) {
450 unreachable!();
452 }
453 }
454
455 fn create_mock_executor_context(
456 current_tick: SimTime,
457 next_tick_status: TickStatus,
458 ) -> (
459 ExecutorContext<TestEvent, TestModel>,
460 SharedHook<TestEvent, TestModel, MockHook>,
461 ) {
462 let test_hook = MockHook::new();
463 let shared_hook = SharedHook::new(test_hook);
464 let mut hook_delegate = HookDelegate::new();
465 hook_delegate.add_shared_hook(shared_hook.clone());
466 let context = ExecutorContext {
467 next_tick_status,
468 current_tick,
469 hook_delegate,
470 source_handler: SourceHandler::new(),
471 event_scheduler: EventScheduler::new(),
472 };
473 (context, shared_hook)
474 }
475
476 #[test]
477 fn test_executor_context_peek_next_tick_no_event() {
478 let current_tick = SimTime::from_ticks(0);
479 let next_tick_status = TickStatus::new(SimTime::from_ticks(1), Duration::zero());
480
481 let (context, _) = create_mock_executor_context(current_tick, next_tick_status);
482
483 let (status, tick_status) = context.peek_next_tick();
484 assert_eq!(status, ExecutorStatus::NoMoreEvent);
485 assert_eq!(tick_status, next_tick_status);
486 }
487
488 #[test]
489 fn test_executor_context_peek_next_tick_with_event() {
490 let current_tick = SimTime::from_ticks(0);
491 let next_tick_status = TickStatus::new(SimTime::from_ticks(1), Duration::zero());
492 let (mut context, _) = create_mock_executor_context(current_tick, next_tick_status);
493
494 context.event_scheduler.schedule(
495 SimTime::from_ticks(5),
496 Duration::ticks(0),
497 EventPriority::minimum(),
498 TestEvent,
499 );
500 context.event_scheduler.flush_pending();
501
502 assert_eq!(
503 context.event_scheduler.peek_next_time(),
504 Some(SimTime::from_ticks(5))
505 );
506
507 let (status, tick_status) = context.peek_next_tick();
508 assert_eq!(status, ExecutorStatus::ExistsMoreEvent);
509 assert_eq!(tick_status, next_tick_status);
510 }
511
512 #[test]
513 fn test_executor_context_begin_tick() {
514 let current_tick = SimTime::from_ticks(0);
515 let next_tick_status = TickStatus::new(SimTime::from_ticks(1), Duration::zero());
516 let (context, shared_hook) = create_mock_executor_context(current_tick, next_tick_status);
517
518 let model = TestModel;
519 let active_context = context.begin_tick(&model);
520
521 assert_eq!(active_context.current_tick_status, next_tick_status);
522 assert_eq!(
523 active_context.next_micro_step_status,
524 MicroStepStatus::initialize()
525 );
526 assert_eq!(shared_hook.get_ref().before_tick_called.borrow().len(), 1);
527 assert_eq!(
528 shared_hook.get_ref().before_tick_called.borrow()[0],
529 (SimTime::from_ticks(1), Duration::zero())
530 );
531 }
532
533 #[test]
534 fn test_executor_context_end_simulation_as_ok() {
535 let current_tick = SimTime::from_ticks(10);
536 let next_tick_status = TickStatus::new(SimTime::from_ticks(11), Duration::zero());
537 let (context, shared_hook) = create_mock_executor_context(current_tick, next_tick_status);
538
539 let model = TestModel;
540 let result: SimulationResult<TestModel, &'static str> = context.end_simulation_as_ok(model);
541
542 assert!(result.is_ok());
543 let output = result.unwrap();
544 assert_eq!(output.last_tick(), current_tick);
545 assert_eq!(
546 shared_hook.get_ref().after_simulation_called.borrow().len(),
547 1
548 );
549 assert_eq!(
550 shared_hook.get_ref().after_simulation_called.borrow()[0],
551 current_tick
552 );
553 }
554
555 #[test]
556 fn test_executor_context_end_simulation_as_error() {
557 let current_tick = SimTime::from_ticks(10);
558 let next_tick_status = TickStatus::new(SimTime::from_ticks(11), Duration::zero());
559 let (context, shared_hook) = create_mock_executor_context(current_tick, next_tick_status);
560
561 let model = TestModel;
562 let error_msg = "Simulation failed";
563 let result = context.end_simulation_as_error(model, error_msg);
564
565 assert!(result.is_err());
566 let error = result.unwrap_err();
567 assert_eq!(error.last_tick(), current_tick);
568 assert_eq!(error.error(), &error_msg);
569 assert_eq!(
570 shared_hook.get_ref().after_simulation_called.borrow().len(),
571 1
572 );
573 assert_eq!(
574 shared_hook.get_ref().after_simulation_called.borrow()[0],
575 current_tick
576 );
577 }
578
579 fn create_mock_active_executor_context(
581 current_tick_status: TickStatus,
582 next_micro_step_status: MicroStepStatus,
583 ) -> (
584 ActiveExecutorContext<TestEvent, TestModel>,
585 SharedHook<TestEvent, TestModel, MockHook>,
586 ) {
587 let test_hook = MockHook::new();
588 let shared_hook = SharedHook::new(test_hook);
589 let mut hook_delegate = HookDelegate::new();
590 hook_delegate.add_shared_hook(shared_hook.clone());
591 let context = ActiveExecutorContext {
592 current_tick_status,
593 next_micro_step_status,
594 hook_delegate,
595 source_handler: SourceHandler::new(),
596 event_scheduler: EventScheduler::new(),
597 };
598 (context, shared_hook)
599 }
600
601 #[test]
602 fn test_active_executor_context_begin_micro_step() {
603 let current_tick_status = TickStatus::new(SimTime::from_ticks(5), Duration::zero());
604 let next_micro_step_status = MicroStepStatus::new(MicroStep::zero());
605 let (context, shared_hook) =
606 create_mock_active_executor_context(current_tick_status, next_micro_step_status);
607
608 let model = TestModel;
609 let micro_step_handler = context.begin_micro_step(&model);
610
611 assert_eq!(
612 micro_step_handler.ref_context().current_tick_status,
613 current_tick_status
614 );
615 assert_eq!(
616 shared_hook
617 .get_ref()
618 .before_micro_step_called
619 .borrow()
620 .len(),
621 1
622 );
623 assert_eq!(
624 shared_hook.get_ref().before_micro_step_called.borrow()[0],
625 (SimTime::from_ticks(5), MicroStep::zero())
626 );
627 }
628
629 #[test]
630 fn test_active_executor_context_end_tick_with_increment_tick() {
631 let current_tick_status = TickStatus::new(SimTime::from_ticks(5), Duration::zero());
632 let mut micro_step_ten = MicroStep::zero();
633 for _ in 0..10 {
634 micro_step_ten = micro_step_ten.next();
635 }
636 let next_micro_step_status = MicroStepStatus::new(micro_step_ten);
637 let (context, shared_hook) =
638 create_mock_active_executor_context(current_tick_status, next_micro_step_status);
639
640 let model = TestModel;
641 let next_context = context.end_tick_with_increment_tick(&model);
642
643 assert_eq!(next_context.current_tick, SimTime::from_ticks(5));
644 assert_eq!(
645 next_context.next_tick_status.current(),
646 SimTime::from_ticks(6)
647 );
648 assert_eq!(next_context.next_tick_status.skipped(), Duration::zero());
649 assert_eq!(shared_hook.get_ref().after_tick_called.borrow().len(), 1);
650 assert_eq!(
651 shared_hook.get_ref().after_tick_called.borrow()[0],
652 (SimTime::from_ticks(5), micro_step_ten)
653 );
654 }
655
656 #[test]
657 fn test_active_executor_context_end_tick_with_jump_to_next_tick_only_source() {
658 let current_tick_status = TickStatus::new(SimTime::from_ticks(5), Duration::zero());
659 let mut micro_step_ten = MicroStep::zero();
660 for _ in 0..10 {
661 micro_step_ten = micro_step_ten.next();
662 }
663 let next_micro_step_status = MicroStepStatus::new(micro_step_ten);
664 let (mut context, shared_hook) =
665 create_mock_active_executor_context(current_tick_status, next_micro_step_status);
666
667 context.source_handler.add_source_after_registered_action(
668 "test source",
669 current_tick_status.current(),
670 Some(Duration::ticks(7)),
671 TestSource {
672 tick: Duration::ticks(3),
673 },
674 );
675 context.source_handler.flush_pending();
676
677 let model = TestModel;
678 let next_context = context.end_tick_with_jump_to_next_tick(&model);
679
680 assert_eq!(next_context.current_tick, SimTime::from_ticks(5));
681 assert_eq!(
682 next_context.next_tick_status.current(),
683 SimTime::from_ticks(12)
684 );
685 assert_eq!(next_context.next_tick_status.skipped(), Duration::ticks(6));
686 assert_eq!(shared_hook.get_ref().after_tick_called.borrow().len(), 1);
687 assert_eq!(
688 shared_hook.get_ref().after_tick_called.borrow()[0],
689 (SimTime::from_ticks(5), micro_step_ten)
690 );
691 }
692
693 #[test]
694 fn test_active_executor_context_end_tick_with_jump_to_next_tick_only_event() {
695 let current_tick_status = TickStatus::new(SimTime::from_ticks(5), Duration::zero());
696 let mut micro_step_ten = MicroStep::zero();
697 for _ in 0..10 {
698 micro_step_ten = micro_step_ten.next();
699 }
700 let next_micro_step_status = MicroStepStatus::new(micro_step_ten);
701 let (mut context, shared_hook) =
702 create_mock_active_executor_context(current_tick_status, next_micro_step_status);
703 context.event_scheduler.schedule(
704 SimTime::from_ticks(5),
705 Duration::ticks(5),
706 EventPriority::minimum(),
707 TestEvent,
708 );
709 context.event_scheduler.flush_pending();
710
711 let model = TestModel;
712 let next_context = context.end_tick_with_jump_to_next_tick(&model);
713
714 assert_eq!(next_context.current_tick, SimTime::from_ticks(5));
715 assert_eq!(
716 next_context.next_tick_status.current(),
717 SimTime::from_ticks(10)
718 );
719 assert_eq!(next_context.next_tick_status.skipped(), Duration::ticks(4));
720 assert_eq!(shared_hook.get_ref().after_tick_called.borrow().len(), 1);
721 assert_eq!(
722 shared_hook.get_ref().after_tick_called.borrow()[0],
723 (SimTime::from_ticks(5), micro_step_ten)
724 );
725 }
726
727 #[test]
728 fn test_active_executor_context_end_tick_with_jump_to_next_tick_both_event_and_source() {
729 let current_tick_status = TickStatus::new(SimTime::from_ticks(5), Duration::zero());
730 let mut micro_step_ten = MicroStep::zero();
731 for _ in 0..10 {
732 micro_step_ten = micro_step_ten.next();
733 }
734 let next_micro_step_status = MicroStepStatus::new(micro_step_ten);
735 let (mut context, shared_hook) =
736 create_mock_active_executor_context(current_tick_status, next_micro_step_status);
737 context.source_handler.add_source_after_registered_action(
738 "test source",
739 current_tick_status.current(),
740 Some(Duration::ticks(7)),
741 TestSource {
742 tick: Duration::ticks(3),
743 },
744 );
745 context.event_scheduler.schedule(
746 SimTime::from_ticks(5),
747 Duration::ticks(5),
748 EventPriority::minimum(),
749 TestEvent,
750 );
751 context.source_handler.flush_pending();
752 context.event_scheduler.flush_pending();
753
754 let model = TestModel;
755 let next_context = context.end_tick_with_jump_to_next_tick(&model);
756
757 assert_eq!(next_context.current_tick, SimTime::from_ticks(5));
758 assert_eq!(
759 next_context.next_tick_status.current(),
760 SimTime::from_ticks(10)
761 ); assert_eq!(next_context.next_tick_status.skipped(), Duration::ticks(4));
763 assert_eq!(shared_hook.get_ref().after_tick_called.borrow().len(), 1);
764 assert_eq!(
765 shared_hook.get_ref().after_tick_called.borrow()[0],
766 (SimTime::from_ticks(5), micro_step_ten)
767 );
768 }
769
770 #[test]
771 fn test_active_executor_context_end_tick_with_jump_to_next_tick_no_next() {
772 let current_tick_status = TickStatus::new(SimTime::from_ticks(5), Duration::zero());
773 let mut micro_step_ten = MicroStep::zero();
774 for _ in 0..10 {
775 micro_step_ten = micro_step_ten.next();
776 }
777 let next_micro_step_status = MicroStepStatus::new(micro_step_ten);
778 let (context, shared_hook) =
779 create_mock_active_executor_context(current_tick_status, next_micro_step_status);
780
781 let model = TestModel;
782 let next_context = context.end_tick_with_jump_to_next_tick(&model);
783
784 assert_eq!(next_context.current_tick, SimTime::from_ticks(5));
785 assert_eq!(
786 next_context.next_tick_status.current(),
787 SimTime::from_ticks(6)
788 );
789 assert_eq!(next_context.next_tick_status.skipped(), Duration::zero());
790 assert_eq!(shared_hook.get_ref().after_tick_called.borrow().len(), 1);
791 assert_eq!(
792 shared_hook.get_ref().after_tick_called.borrow()[0],
793 (SimTime::from_ticks(5), micro_step_ten)
794 );
795 }
796
797 #[test]
798 fn test_active_executor_context_discard_remain_micro_step() {
799 let current_tick_status = TickStatus::new(SimTime::from_ticks(5), Duration::zero());
800 let mut micro_step_ten = MicroStep::zero();
801 for _ in 0..10 {
802 micro_step_ten = micro_step_ten.next();
803 }
804 let next_micro_step_status = MicroStepStatus::new(micro_step_ten);
805 let (mut context, shared_hook) =
806 create_mock_active_executor_context(current_tick_status, next_micro_step_status);
807
808 context.source_handler.add_source_after_registered_action(
809 "test source",
810 current_tick_status.current(),
811 Some(Duration::ticks(0)),
812 TestSource {
813 tick: Duration::ticks(3),
814 },
815 );
816 context.event_scheduler.schedule(
817 SimTime::from_ticks(5),
818 Duration::ticks(0),
819 EventPriority::minimum(),
820 TestEvent,
821 );
822 context.event_scheduler.schedule(
823 SimTime::from_ticks(5),
824 Duration::ticks(0),
825 EventPriority::minimum(),
826 TestEvent,
827 );
828 context.source_handler.flush_pending();
829 context.event_scheduler.flush_pending();
830
831 let model = TestModel;
832 let (discarded_sources, discarded_events) = context.discard_remain_micro_step(&model);
833
834 assert_eq!(discarded_sources.len(), 1);
835 assert_eq!(discarded_sources[0].name(), "test source");
836
837 assert_eq!(discarded_events.len(), 2);
838 assert_eq!(discarded_events[0].payload, TestEvent);
839 assert_eq!(discarded_events[1].payload, TestEvent);
840
841 assert_eq!(
842 shared_hook
843 .get_ref()
844 .on_discard_remain_micro_step_called
845 .borrow()
846 .len(),
847 1
848 );
849 assert_eq!(
850 shared_hook
851 .get_ref()
852 .on_discard_remain_micro_step_called
853 .borrow()[0],
854 (SimTime::from_ticks(5), micro_step_ten, 1, 2)
855 );
856 }
857}