xdevs/modeling/
component.rs

1use super::port::{Bag, InPort, OutPort, Port};
2use crate::DynRef;
3use std::collections::HashMap;
4use std::sync::Arc;
5
6/// DEVS component. Models must comprise a component to fulfill the [`crate::simulation::Simulator`] trait.
7pub struct Component {
8    /// Name of the DEVS component.
9    name: String,
10    /// Time of the last component state transition.
11    t_last: f64,
12    /// Time for the next component state transition.
13    t_next: f64,
14    /// Input ports map. Keys are the port IDs, and values correspond to the index of the port in `in_ports`.
15    in_map: HashMap<String, usize>,
16    /// Output ports map. Keys are the port IDs, and values correspond to the index of the port in `out_ports`.
17    out_map: HashMap<String, usize>,
18    /// Input port set of the DEVS component (serialized for better performance).
19    in_ports: Vec<Arc<dyn Port>>,
20    /// Output port set of the DEVS component (serialized for better performance).
21    out_ports: Vec<Arc<dyn Port>>,
22}
23
24impl Component {
25    /// It creates a new component with the provided name.
26    pub fn new(name: &str) -> Self {
27        Self {
28            name: name.to_string(),
29            t_last: 0.,
30            t_next: f64::INFINITY,
31            in_map: HashMap::new(),
32            out_map: HashMap::new(),
33            in_ports: Vec::new(),
34            out_ports: Vec::new(),
35        }
36    }
37
38    /// Returns name of the component.
39    #[inline]
40    pub fn get_name(&self) -> &str {
41        &self.name
42    }
43
44    /// Returns the time for the last component state transition.
45    #[inline]
46    pub fn get_t_last(&self) -> f64 {
47        self.t_last
48    }
49
50    /// Returns the time for the next component state transition.
51    #[inline]
52    pub fn get_t_next(&self) -> f64 {
53        self.t_next
54    }
55
56    /// Sets the time for the for the last and next component state transitions.
57    #[inline]
58    pub(crate) fn set_sim_t(&mut self, t_last: f64, t_next: f64) {
59        self.t_last = t_last;
60        self.t_next = t_next;
61    }
62
63    /// Adds a new input port of type `T` and returns a reference to it.
64    /// It panics if there is already an input port with the same name.
65    pub fn add_in_port<T: DynRef + Clone>(&mut self, name: &str) -> InPort<T> {
66        if self.in_map.contains_key(name) {
67            panic!("component already contains input port with the name provided");
68        }
69        self.in_map.insert(name.to_string(), self.in_ports.len());
70        let bag = Bag::new();
71        self.in_ports.push(bag.clone());
72        InPort(bag)
73    }
74
75    /// Adds a new output port of type `T` and returns a reference to it.
76    /// It panics if there is already an output port with the same name.
77    pub fn add_out_port<T: DynRef + Clone>(&mut self, name: &str) -> OutPort<T> {
78        if self.out_map.contains_key(name) {
79            panic!("component already contains output port with the name provided");
80        }
81        self.out_map.insert(name.to_string(), self.out_ports.len());
82        let bag = Bag::new();
83        self.out_ports.push(bag.clone());
84        OutPort(bag)
85    }
86
87    /// Returns `true` if all the input ports of the model are empty.
88    ///
89    /// # Safety
90    ///
91    /// This method can only be executed when implementing the [`crate::simulation::Simulator::transition`]
92    /// method to determine whether to execute the internal, external, or confluent transition function.
93    #[inline]
94    pub(crate) unsafe fn is_input_empty(&self) -> bool {
95        self.in_ports.iter().all(|p| p.is_empty())
96    }
97
98    /// Returns a reference to an input port with the given name.
99    /// If the component does not have any input port with this name, it returns [`None`].
100    #[inline]
101    pub(crate) fn get_in_port(&self, port_name: &str) -> Option<Arc<dyn Port>> {
102        let i = *self.in_map.get(port_name)?;
103        Some(self.in_ports.get(i)?.clone())
104    }
105
106    /// Returns a reference to an output port with the given name.
107    /// If the component does not have any output port with this name, it returns [`None`].
108    #[inline]
109    pub(crate) fn get_out_port(&self, port_name: &str) -> Option<Arc<dyn Port>> {
110        let i = *self.out_map.get(port_name)?;
111        Some(self.out_ports.get(i)?.clone())
112    }
113
114    /// Clears all the input ports of the model.
115    ///
116    /// # Safety
117    ///
118    /// This method can only be executed when implementing [`crate::simulation::Simulator::clear_ports`] method.
119    #[inline]
120    pub(crate) unsafe fn clear_input(&mut self) {
121        self.in_ports.iter_mut().for_each(|p| p.clear());
122    }
123
124    /// Clears all the output ports of the model.
125    ///
126    /// # Safety
127    ///
128    /// This method can only be executed when implementing [`crate::simulation::Simulator::clear_ports`] method.
129    #[inline]
130    pub(crate) unsafe fn clear_output(&mut self) {
131        self.out_ports.iter_mut().for_each(|p| p.clear());
132    }
133}