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}