1use crate::context::{SourceContext, UserContext};
8use crate::execution::phase::MicroStepHandler;
9use crate::modeling::hook::Hook;
10use crate::modeling::model::Model;
11use crate::source_handler::SourceHandler;
12use crate::source_handler::{SourceReadyEntry, SourceView};
13use std::collections::VecDeque;
14
15pub struct SourcePhase<E, M: Model<E>> {
20 context: SourceContext<E, M>,
21 pub(crate) source_handler: Option<SourceHandler<E, M>>,
26 ready_sources: VecDeque<SourceReadyEntry>,
27}
28
29impl<E, M: Model<E>> SourcePhase<E, M> {
30 pub(crate) fn new(
32 context: SourceContext<E, M>,
33 source_handler: SourceHandler<E, M>,
34 ready_sources: VecDeque<SourceReadyEntry>,
35 ) -> Self {
36 SourcePhase {
37 context,
38 source_handler: Some(source_handler),
39 ready_sources,
40 }
41 }
42
43 pub fn get_context(&mut self) -> &mut SourceContext<E, M> {
45 &mut self.context
46 }
47
48 pub fn get_source_view(&self, ready_entry: &SourceReadyEntry) -> SourceView {
50 SourceView::new(ready_entry.source_id(), ready_entry.clone_name_arc())
51 }
52
53 pub fn complete_source_phase(self, model: &M) -> MicroStepHandler<SourceContext<E, M>> {
58 self.context.hook().after_source_phase(
59 model,
60 self.context.current_tick(),
61 self.context.current_micro_step(),
62 );
63
64 let mut context = self.context;
65 context.source_handler = self.source_handler;
66 MicroStepHandler::new(context)
67 }
68
69 pub fn take_one(&mut self) -> Option<SourceReadyEntry> {
71 self.ready_sources.pop_front()
72 }
73
74 pub fn take_one_if<F>(&mut self, predicate: F) -> Option<SourceReadyEntry>
76 where
77 F: FnOnce(&SourceReadyEntry) -> bool,
78 {
79 self.ready_sources.pop_front_if(|e| predicate(e))
80 }
81
82 pub fn take_front_if<F>(&mut self, predicate: F) -> Option<SourceReadyEntry>
84 where
85 F: FnOnce(&SourceReadyEntry) -> bool,
86 {
87 if self.ready_sources.front().is_some_and(predicate) {
88 self.ready_sources.pop_front()
89 } else {
90 None
91 }
92 }
93
94 pub fn take_all(&mut self) -> VecDeque<SourceReadyEntry> {
96 std::mem::take(&mut self.ready_sources)
97 }
98
99 pub fn take_all_if<F>(&mut self, predicate: F) -> VecDeque<SourceReadyEntry>
103 where
104 F: FnMut(&SourceReadyEntry) -> bool,
105 {
106 let all_sources = std::mem::take(&mut self.ready_sources);
107
108 let (taken, remaining): (VecDeque<_>, VecDeque<_>) =
109 all_sources.into_iter().partition(predicate);
110
111 self.ready_sources = remaining;
112
113 taken
114 }
115
116 pub fn fire_and_schedule(&mut self, model: &M, entry: SourceReadyEntry) {
120 let now = self.context.current_tick();
121 let current_microstep = self.context.current_micro_step();
122 let view = self.get_source_view(&entry);
123
124 self.context
125 .hook()
126 .before_source(model, now, current_microstep, &view);
127
128 let source_handler = self
129 .source_handler
130 .as_mut()
131 .expect("SourcePhase: source_handler is not properly initialized.");
132
133 let source_id = entry.source_id();
134 let entry = source_handler.get_by_source_id(source_id);
135 let next_fire_delay_optional = entry.source.fire(&mut self.context, model);
136
137 if let Some(next_fire_delay) = next_fire_delay_optional {
138 source_handler.schedule_next(now, next_fire_delay, source_id);
139 }
140
141 let computed_next_scheduled_at = next_fire_delay_optional.map(|d| now + d);
142
143 self.context.hook().after_source(
144 model,
145 now,
146 current_microstep,
147 &view,
148 computed_next_scheduled_at,
149 );
150 }
151
152 pub fn discard(&mut self, model: &M, entry: SourceReadyEntry) {
156 let view = self.get_source_view(&entry);
157
158 self.context.hook().discard_source(
159 model,
160 self.context.current_tick(),
161 self.context.current_micro_step(),
162 &view,
163 );
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use crate::context::{EventContext, UserContext};
171 use crate::event_scheduler::EventScheduler;
172 use crate::modeling::event::Event;
173 use crate::modeling::hook::Hook;
174 use crate::modeling::hook::instance::{HookDelegate, SharedHook};
175 use crate::modeling::model::Model;
176 use crate::primitive::id::SourceId;
177 use crate::primitive::time::{Duration, MicroStep, MicroStepStatus, SimTime, TickStatus};
178 use std::collections::VecDeque;
179 use std::rc::Rc;
180 use std::sync::{Arc, Mutex};
181
182 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
183 enum TestEvent {}
184
185 struct TestModel {
186 handled_events: Vec<TestEvent>,
187 }
188
189 impl Model<TestEvent> for TestModel {
190 fn handle_event(
191 &mut self,
192 _context: &mut EventContext<TestEvent, Self>,
193 event: &Event<TestEvent>,
194 ) {
195 self.handled_events.push(event.payload);
196 }
197 }
198
199 struct DiscardHook {
201 discarded_events: Rc<Mutex<Vec<TestEvent>>>,
202 discarded_sources: Rc<Mutex<Vec<SourceId>>>,
203 }
204
205 impl Hook<TestEvent, TestModel> for DiscardHook {
206 fn before_simulation(&self, _model: &TestModel) {
207 }
209
210 fn after_simulation(&self, _model: &TestModel, _end_tick: SimTime) {
211 }
213 fn before_tick(
214 &self,
215 _model: &TestModel,
216 _current_tick: SimTime,
217 _skipped_duration: Duration,
218 ) {
219 }
221 fn after_tick(
222 &self,
223 _model: &TestModel,
224 _current_tick: SimTime,
225 _last_micro_step: MicroStep,
226 ) {
227 }
229 fn before_micro_step(
230 &self,
231 _model: &TestModel,
232 _current_tick: SimTime,
233 _current_micro_step: MicroStep,
234 ) {
235 }
237 fn after_micro_step(
238 &self,
239 _model: &TestModel,
240 _current_tick: SimTime,
241 _current_micro_step: MicroStep,
242 ) {
243 }
245 fn on_discard_remain_micro_step(
246 &self,
247 _model: &TestModel,
248 _current_tick: SimTime,
249 _first_discarded_micro_step: MicroStep,
250 _discarded_sources: &[SourceReadyEntry],
251 _discarded_events: &[Event<TestEvent>],
252 ) {
253 }
255 fn before_register_source(&self, _model: &TestModel, _name: &str) {
256 }
258 fn after_register_source(&self, _model: &TestModel, _name: &str) {
259 }
261 fn before_source_phase(
262 &self,
263 _model: &TestModel,
264 _current_tick: SimTime,
265 _current_micro_step: MicroStep,
266 ) {
267 }
269 fn before_source(
270 &self,
271 _model: &TestModel,
272 _current_tick: SimTime,
273 _current_micro_step: MicroStep,
274 _source_view: &SourceView,
275 ) {
276 }
278 fn after_source(
279 &self,
280 _model: &TestModel,
281 _current_tick: SimTime,
282 _current_micro_step: MicroStep,
283 _source_view: &SourceView,
284 _computed_next_fire: Option<SimTime>,
285 ) {
286 }
288 fn cancel_source(
289 &self,
290 _model: &TestModel,
291 _current_tick: SimTime,
292 _current_micro_step: MicroStep,
293 _scheduled_at: SimTime,
294 _source_view: &SourceView,
295 ) {
296 }
298 fn discard_source(
299 &self,
300 _model: &TestModel,
301 _current_tick: SimTime,
302 _current_micro_step: MicroStep,
303 source_view: &SourceView,
304 ) {
305 self.discarded_sources
306 .lock()
307 .unwrap()
308 .push(source_view.source_id());
309 }
310 fn after_source_phase(
311 &self,
312 _model: &TestModel,
313 _current_tick: SimTime,
314 _current_micro_step: MicroStep,
315 ) {
316 }
318 fn before_event_phase(
319 &self,
320 _model: &TestModel,
321 _current_tick: SimTime,
322 _current_micro_step: MicroStep,
323 ) {
324 }
326 fn before_event(
327 &self,
328 _model: &TestModel,
329 _current_tick: SimTime,
330 _current_micro_step: MicroStep,
331 _event: &Event<TestEvent>,
332 ) {
333 }
335 fn after_event(
336 &self,
337 _model: &TestModel,
338 _current_tick: SimTime,
339 _current_micro_step: MicroStep,
340 _event: &Event<TestEvent>,
341 ) {
342 }
344 fn cancel_event(
345 &self,
346 _model: &TestModel,
347 _current_tick: SimTime,
348 _current_micro_step: MicroStep,
349 _scheduled_at: SimTime,
350 _event: &Event<TestEvent>,
351 ) {
352 }
354 fn discard_event(
355 &self,
356 _model: &TestModel,
357 _current_tick: SimTime,
358 _current_micro_step: MicroStep,
359 event: &Event<TestEvent>,
360 ) {
361 self.discarded_events.lock().unwrap().push(event.payload);
362 }
363 fn after_event_phase(
364 &self,
365 _model: &TestModel,
366 _current_tick: SimTime,
367 _current_micro_step: MicroStep,
368 ) {
369 }
371 }
372
373 fn setup_source_phase() -> (SourcePhase<TestEvent, TestModel>, TestModel) {
375 let model = TestModel {
376 handled_events: Vec::new(),
377 };
378
379 let source_context = SourceContext {
381 current_tick_status: TickStatus::initialize(),
382 current_micro_step_status: MicroStepStatus::initialize(),
383 hook_delegate: HookDelegate::new(),
384 source_handler: None,
385 event_scheduler: EventScheduler::new(),
386 };
387
388 let source_handler = SourceHandler::new();
389
390 let mut ready_sources = VecDeque::new();
391 ready_sources.push_back(SourceReadyEntry::new(
392 SourceId::new(1),
393 Arc::from("SourceA"),
394 ));
395 ready_sources.push_back(SourceReadyEntry::new(
396 SourceId::new(2),
397 Arc::from("SourceB"),
398 ));
399 ready_sources.push_back(SourceReadyEntry::new(
400 SourceId::new(3),
401 Arc::from("SourceC"),
402 ));
403
404 let source_phase = SourcePhase::new(source_context, source_handler, ready_sources);
405
406 (source_phase, model)
407 }
408
409 #[test]
410 fn test_new() {
411 let (source_phase, _) = setup_source_phase();
412 assert_eq!(source_phase.ready_sources.len(), 3);
413 assert!(source_phase.source_handler.is_some());
414 }
415
416 #[test]
417 fn test_get_context() {
418 let (mut source_phase, _) = setup_source_phase();
419 let context = source_phase.get_context();
420 assert_eq!(context.current_tick(), SimTime::zero());
421 }
422
423 #[test]
424 fn test_get_source_view() {
425 let (source_phase, _) = setup_source_phase();
426 let entry = SourceReadyEntry::new(SourceId::new(1), Arc::from("SourceA"));
427 let view = source_phase.get_source_view(&entry);
428 assert_eq!(view.source_id(), SourceId::new(1));
429 assert_eq!(view.name(), "SourceA");
430 }
431
432 #[test]
433 fn test_take_one() {
434 let (mut source_phase, _) = setup_source_phase();
435 let entry = source_phase.take_one().unwrap();
436 assert_eq!(entry.source_id(), SourceId::new(1));
437 assert_eq!(source_phase.ready_sources.len(), 2);
438 }
439
440 #[test]
441 fn test_take_front_if() {
442 let (mut source_phase, _) = setup_source_phase();
443 let entry_a = source_phase
444 .take_front_if(|e| e.source_id() == SourceId::new(1))
445 .unwrap();
446 assert_eq!(entry_a.source_id(), SourceId::new(1));
447 assert_eq!(source_phase.ready_sources.len(), 2);
448
449 let entry_c = source_phase.take_front_if(|e| e.source_id() == SourceId::new(3));
450 assert!(entry_c.is_none());
451 assert_eq!(source_phase.ready_sources.len(), 2);
452 }
453
454 #[test]
455 fn test_take_all() {
456 let (mut source_phase, _) = setup_source_phase();
457 let all_entries = source_phase.take_all();
458 assert_eq!(all_entries.len(), 3);
459 assert_eq!(source_phase.ready_sources.len(), 0);
460 }
461
462 #[test]
463 fn test_take_all_if() {
464 let (mut source_phase, _) = setup_source_phase();
465 source_phase.ready_sources.push_back(SourceReadyEntry::new(
466 SourceId::new(1),
467 Arc::from("SourceA_again"),
468 ));
469
470 let taken_entries = source_phase.take_all_if(|e| e.source_id() == SourceId::new(1));
471 assert_eq!(taken_entries.len(), 2);
472 assert_eq!(taken_entries.front().unwrap().source_id(), SourceId::new(1));
473 assert_eq!(taken_entries.get(1).unwrap().source_id(), SourceId::new(1));
474
475 assert_eq!(source_phase.ready_sources.len(), 2);
476 assert_eq!(
477 source_phase.ready_sources.front().unwrap().source_id(),
478 SourceId::new(2)
479 );
480 assert_eq!(
481 source_phase.ready_sources.get(1).unwrap().source_id(),
482 SourceId::new(3)
483 );
484 }
485
486 #[test]
487 fn test_fire_and_schedule() {
488 let (source_phase, _) = setup_source_phase();
489 assert!(source_phase.source_handler.is_some());
490 }
491
492 #[test]
493 fn test_discard() {
494 let (mut source_phase, model) = setup_source_phase();
495
496 let hook = SharedHook::new(DiscardHook {
497 discarded_events: Rc::new(Mutex::new(Vec::new())),
498 discarded_sources: Rc::new(Mutex::new(Vec::new())),
499 });
500
501 source_phase
502 .get_context()
503 .hook_delegate
504 .add_shared_hook(hook.clone());
505
506 let source_a_entry = source_phase.take_one().unwrap();
507 source_phase.discard(&model, source_a_entry);
508
509 assert_eq!(hook.get_ref().discarded_sources.lock().unwrap().len(), 1);
510 assert_eq!(
511 hook.get_ref().discarded_sources.lock().unwrap()[0],
512 SourceId::new(1)
513 );
514 }
515
516 #[test]
517 fn test_complete_source_phase() {
518 let (source_phase, model) = setup_source_phase();
519 let micro_step_handler = source_phase.complete_source_phase(&model);
520
521 assert_eq!(
522 micro_step_handler.ref_context().current_tick(),
523 SimTime::zero()
524 );
525 assert!(micro_step_handler.ref_context().source_handler.is_some());
526 }
527}