Skip to main content

des_sim/execution/strategy/continue_strategy/
always_continue.rs

1//! The `always_continue` module provides the `AlwaysContinueStrategy`, a simple implementation
2//! of the `ContinueStrategy` trait.
3//!
4//! This strategy unconditionally allows the simulation to proceed to the next micro-step,
5//! effectively delegating termination control to the main simulation loop's `should_stop`
6//! condition or the natural exhaustion of events.
7
8use crate::execution::phase::UncheckedActiveExecutor;
9use crate::execution::strategy::{ContinueStrategy, ContinuousStrategyResult};
10use crate::modeling::model::Model;
11
12/// A default strategy that unconditionally allows simulation continuation.
13///
14/// Since this strategy imposes no termination criteria, the simulation proceeds
15/// until the global stop condition (`should_stop`) is met or the model's
16/// internal logic completes naturally.
17#[derive(Clone)]
18pub struct AlwaysContinueStrategy;
19
20impl Default for AlwaysContinueStrategy {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26impl<E, M: Model<E>, RunnerError> ContinueStrategy<E, M, RunnerError> for AlwaysContinueStrategy {
27    type Err = RunnerError;
28
29    /// Always returns `Ok`, authorizing the execution engine to proceed to the
30    /// next micro-step.
31    fn handle_micro_step_continue(
32        &mut self,
33        _model: &M,
34        unchecked: UncheckedActiveExecutor<E, M>,
35    ) -> ContinuousStrategyResult<E, M, Self::Err> {
36        Ok(unchecked.into_active_executor())
37    }
38}
39
40impl AlwaysContinueStrategy {
41    /// Creates a new `AlwaysContinueStrategy`.
42    pub fn new() -> Self {
43        Self
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use crate::context::{ActiveExecutorContext, EventContext};
51    use crate::event_scheduler::EventScheduler;
52    use crate::modeling::event::Event;
53    use crate::modeling::hook::instance::HookDelegate;
54    use crate::primitive::time::{MicroStep, MicroStepStatus, TickStatus};
55    use crate::source_handler::SourceHandler;
56
57    /// Dummy event for testing.
58    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
59    enum TestEvent {}
60
61    /// Dummy model for testing.
62    #[derive(Debug, Clone)]
63    struct TestModel;
64
65    impl Model<TestEvent> for TestModel {
66        fn handle_event(
67            &mut self,
68            _context: &mut EventContext<TestEvent, Self>,
69            _event: &Event<TestEvent>,
70        ) {
71        }
72    }
73
74    #[test]
75    #[allow(clippy::default_constructed_unit_structs)]
76    fn test_always_continue_strategy_default_and_new() {
77        let _strategy_new = AlwaysContinueStrategy::new();
78        let _strategy_default = AlwaysContinueStrategy::default();
79    }
80
81    #[test]
82    fn test_always_continue_strategy_handle_continue() {
83        let model = TestModel;
84
85        // Prepare the simulation context.
86        let active_context = ActiveExecutorContext {
87            current_tick_status: TickStatus::initialize(),
88            next_micro_step_status: MicroStepStatus::initialize(),
89            hook_delegate: HookDelegate::new(),
90            source_handler: SourceHandler::new(),
91            event_scheduler: EventScheduler::new(),
92        };
93
94        // Create the execution state.
95        let current_micro_step = MicroStep::zero();
96        let unchecked_executor = UncheckedActiveExecutor::new(active_context, current_micro_step);
97
98        let mut strategy = AlwaysContinueStrategy::new();
99
100        // Validate strategy execution.
101        let result: ContinuousStrategyResult<TestEvent, TestModel, ()> =
102            strategy.handle_micro_step_continue(&model, unchecked_executor);
103
104        assert!(result.is_ok(), "Continuation strategy failed unexpectedly.");
105
106        let returned_context = result.map_err(|e| e.1).unwrap();
107
108        // Verify that the context information is correctly preserved.
109        assert_eq!(
110            returned_context.current_tick_status.current(),
111            crate::primitive::time::SimTime::zero()
112        );
113    }
114}