Skip to main content

des_sim/modeling/hook/instance/
interactive_step.rs

1//! The `interactive_step` module provides the `InteractiveStepHook`, a utility
2//! for debugging and interactive control of a simulation.
3//!
4//! This hook pauses the simulation at the beginning of each tick, prompting the user
5//! to press Enter to proceed. This allows for step-by-step inspection of the simulation
6//! state, making it invaluable for understanding complex simulation dynamics.
7
8use crate::modeling::event::Event;
9use crate::modeling::hook::Hook;
10use crate::modeling::model::Model;
11use crate::primitive::time::{Duration, MicroStep, SimTime};
12use crate::source_handler::{SourceReadyEntry, SourceView};
13use std::io;
14use std::io::Write;
15
16/// A hook that pauses the simulation at each tick to allow for interactive inspection.
17pub struct InteractiveStepHook;
18
19impl<E, M: Model<E>> Hook<E, M> for InteractiveStepHook {
20    fn before_simulation(&self, _model: &M) {
21        // No-op
22    }
23
24    fn after_simulation(&self, _model: &M, _end_tick: SimTime) {
25        println!("[Interactive Step Hook] Simulation halted: termination condition reached.");
26    }
27
28    fn before_tick(&self, _model: &M, current_tick: SimTime, skipped_duration: Duration) {
29        println!("================ [Interactive Step Hook] ================");
30        println!("  Current Tick          : {:?}", current_tick);
31        println!("  Skipped Duration      : {} ticks", skipped_duration);
32        println!("--------------------------------------------------------");
33
34        print!(
35            "[Interactive Step Hook] Press Enter to process this tick (source/event phases)... "
36        );
37
38        if cfg!(test) || cfg!(feature = "des_sim_test_mode") {
39            // Skip waiting during tests to prevent blocking
40            return;
41        }
42
43        let _ = io::stdout().flush(); // Ensure prompt is displayed
44
45        // Block thread until user presses Enter
46        let mut input = String::new();
47        let _ = io::stdin().read_line(&mut input);
48    }
49
50    fn after_tick(&self, _model: &M, current_tick: SimTime, last_micro_step: MicroStep) {
51        println!(
52            "[Interactive Step Hook] Finished processing tick {}. (Count micro-steps: {})",
53            current_tick,
54            // Adjust 0-indexed micro-step to count
55            last_micro_step.value() + 1
56        );
57        println!("========================================================\n");
58    }
59
60    fn before_micro_step(
61        &self,
62        _model: &M,
63        _current_tick: SimTime,
64        _current_micro_step: MicroStep,
65    ) {
66        // No-op
67    }
68
69    fn after_micro_step(&self, _model: &M, _current_tick: SimTime, _current_micro_step: MicroStep) {
70        // No-op
71    }
72
73    fn on_discard_remain_micro_step(
74        &self,
75        _model: &M,
76        _current_tick: SimTime,
77        _first_discarded_micro_step: MicroStep,
78        _discarded_sources: &[SourceReadyEntry],
79        _discarded_events: &[Event<E>],
80    ) {
81        // No-op
82    }
83
84    fn before_register_source(&self, _model: &M, _name: &str) {
85        // No-op
86    }
87
88    fn after_register_source(&self, _model: &M, _name: &str) {
89        // No-op
90    }
91
92    fn before_source_phase(
93        &self,
94        _model: &M,
95        _current_tick: SimTime,
96        _current_micro_step: MicroStep,
97    ) {
98        // No-op
99    }
100
101    fn before_source(
102        &self,
103        _model: &M,
104        _current_tick: SimTime,
105        _current_micro_step: MicroStep,
106        _source_view: &SourceView,
107    ) {
108        // No-op
109    }
110
111    fn after_source(
112        &self,
113        _model: &M,
114        _current_tick: SimTime,
115        _current_micro_step: MicroStep,
116        _source_view: &SourceView,
117        _computed_next_fire: Option<SimTime>,
118    ) {
119        // No-op
120    }
121
122    fn cancel_source(
123        &self,
124        _model: &M,
125        _current_tick: SimTime,
126        _current_micro_step: MicroStep,
127        _scheduled_at: SimTime,
128        _source_view: &SourceView,
129    ) {
130        // No-op
131    }
132
133    fn discard_source(
134        &self,
135        _model: &M,
136        _current_tick: SimTime,
137        _current_micro_step: MicroStep,
138        _source_view: &SourceView,
139    ) {
140        // No-op
141    }
142
143    fn after_source_phase(
144        &self,
145        _model: &M,
146        _current_tick: SimTime,
147        _current_micro_step: MicroStep,
148    ) {
149        // No-op
150    }
151
152    fn before_event_phase(
153        &self,
154        _model: &M,
155        _current_tick: SimTime,
156        _current_micro_step: MicroStep,
157    ) {
158        // No-op
159    }
160
161    fn before_event(
162        &self,
163        _model: &M,
164        _current_tick: SimTime,
165        _current_micro_step: MicroStep,
166        _event: &Event<E>,
167    ) {
168        // No-op
169    }
170
171    fn after_event(
172        &self,
173        _model: &M,
174        _current_tick: SimTime,
175        _current_micro_step: MicroStep,
176        _event: &Event<E>,
177    ) {
178        // No-op
179    }
180
181    fn cancel_event(
182        &self,
183        _model: &M,
184        _current_tick: SimTime,
185        _current_micro_step: MicroStep,
186        _scheduled_at: SimTime,
187        _event: &Event<E>,
188    ) {
189        // No-op
190    }
191
192    fn discard_event(
193        &self,
194        _model: &M,
195        _current_tick: SimTime,
196        _current_micro_step: MicroStep,
197        _event: &Event<E>,
198    ) {
199        // No-op
200    }
201
202    fn after_event_phase(
203        &self,
204        _model: &M,
205        _current_tick: SimTime,
206        _current_micro_step: MicroStep,
207    ) {
208        // No-op
209    }
210}