1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use crate::aux::AbstractSimulator;

#[cfg(feature = "std")]
pub mod std;

/// A DEVS simulator that uses a virtual clock (i.e., no real time is used).
pub struct Simulator<M: AbstractSimulator> {
    model: M,
}

impl<M: AbstractSimulator> Simulator<M> {
    #[inline]
    pub const fn new(model: M) -> Self {
        Self { model }
    }

    /// It executes the simulation of the inner DEVS model from `t_start` to `t_stop`.
    /// It provides support for real time execution via the following arguments:
    ///
    /// - `wait_until`: a closure that is called between state transitions.
    /// It receives the time of the next state transition and a mutable reference to the input ports.
    /// It returns the actual time "waited".
    /// If the returned time is equal to the input time, an internal/confluent state transition is performed.
    /// Otherwise, it assumes that an external event happened and executes the external transition function.
    /// - `propagate_output`: a closure that is called after output functions.
    /// It receives a mutable reference to the output ports so the closure can access to output events.
    /// Feel free to ignore this argument if you do not need to propagate output messages.
    #[inline]
    pub fn simulate_rt(
        &mut self,
        t_start: f64,
        t_stop: f64,
        mut wait_until: impl FnMut(f64, &mut M::Input) -> f64,
        mut propagate_output: impl FnMut(&M::Output),
    ) {
        let mut t = t_start;
        let mut t_next_internal = self.model.start(t);
        while t < t_stop {
            let t_until = if t_next_internal > t_stop {
                t_stop
            } else {
                t_next_internal
            };

            t = wait_until(t_until, self.model.get_input_mut());
            if t >= t_next_internal {
                self.model.lambda(t);
                propagate_output(self.model.get_output());
            }
            t_next_internal = self.model.delta(t);
        }
        self.model.stop(t_stop);
    }

    /// It executes the simulation of the inner DEVS model from `t_start` to `t_stop`.
    /// It uses a virtual clock (i.e., no real time is used).
    #[inline]
    pub fn simulate_vt(&mut self, t_start: f64, t_stop: f64) {
        self.simulate_rt(t_start, t_stop, |t, _| t, |_| {});
    }
}