simrs/
component.rs

1use std::collections::HashMap;
2use std::fmt;
3
4use crate::{generate_next_id, ComponentId, EventEntry, Scheduler, State};
5
6pub trait ProcessEventEntry {
7    fn process_event_entry(&self, entry: EventEntry, scheduler: &mut Scheduler, state: &mut State);
8}
9
10/// Interface of a simulation component.
11pub trait Component: ProcessEventEntry {
12    /// Type of event the component reacts to.
13    type Event: fmt::Debug + 'static;
14
15    /// Reacts to `event`. A component has access to the following elements of the simulation:
16    /// - `self_id`: This is the ID of this component. This is used to schedule events to itself.
17    ///              This is passed for convenience, as the ID is only known after the component
18    ///              has been already constructed and passed to the simulation.
19    /// - `event`: The occurring event.
20    /// - `scheduler`: The scheduler used to access time and schedule new events.
21    /// - `state`: The state is used to access queues and values in the value store.
22    fn process_event(
23        &self,
24        self_id: ComponentId<Self::Event>,
25        event: &Self::Event,
26        scheduler: &mut Scheduler,
27        state: &mut State,
28    );
29}
30
31impl<E, C> ProcessEventEntry for C
32where
33    E: fmt::Debug + 'static,
34    C: Component<Event = E>,
35{
36    fn process_event_entry(&self, entry: EventEntry, scheduler: &mut Scheduler, state: &mut State) {
37        let entry = entry
38            .downcast::<E>()
39            .expect("Failed to downcast event entry.");
40        self.process_event(entry.component_id, entry.event, scheduler, state);
41    }
42}
43
44/// Container holding type-erased components.
45#[derive(Default)]
46pub struct Components {
47    components: HashMap<usize, Box<dyn ::std::any::Any>>,
48}
49
50impl Components {
51    #[allow(clippy::missing_panics_doc)]
52    /// Process the event on the component given by the event entry.
53    pub fn process_event_entry(
54        &self,
55        entry: EventEntry,
56        scheduler: &mut Scheduler,
57        state: &mut State,
58    ) {
59        self.components
60            .get(&entry.component_idx())
61            .unwrap()
62            .downcast_ref::<Box<dyn ProcessEventEntry>>()
63            .expect("Failed to downcast component.")
64            .process_event_entry(entry, scheduler, state);
65    }
66
67    /// Registers a new component and returns its ID.
68    #[must_use]
69    pub fn add_component<E: fmt::Debug + 'static, C: Component<Event = E> + 'static>(
70        &mut self,
71        component: C,
72    ) -> ComponentId<E> {
73        let id = generate_next_id();
74        let component: Box<dyn ProcessEventEntry> = Box::new(component);
75        self.components.insert(id, Box::new(component));
76        ComponentId::new(id)
77    }
78}
79
80#[cfg(test)]
81mod test {
82    use super::*;
83    use std::cell::RefCell;
84    use std::rc::Rc;
85
86    struct TestComponent(Rc<RefCell<String>>);
87
88    impl Component for TestComponent {
89        type Event = String;
90
91        fn process_event(
92            &self,
93            _self_id: ComponentId<Self::Event>,
94            event: &Self::Event,
95            _scheduler: &mut Scheduler,
96            _state: &mut State,
97        ) {
98            *self.0.borrow_mut() = event.clone();
99        }
100    }
101
102    struct RcTestComponent(String);
103
104    impl Component for Rc<RefCell<RcTestComponent>> {
105        type Event = String;
106
107        fn process_event(
108            &self,
109            _self_id: ComponentId<Self::Event>,
110            event: &Self::Event,
111            _scheduler: &mut Scheduler,
112            _state: &mut State,
113        ) {
114            self.borrow_mut().0 = event.clone();
115        }
116    }
117
118    #[test]
119    fn test_add_and_get_component() {
120        let mut scheduler = Scheduler::default();
121        let mut state = State::default();
122        let mut components = Components::default();
123        assert_eq!(components.components.len(), 0);
124
125        let text = Rc::new(RefCell::new(String::from("")));
126
127        let comp: ComponentId<String> = components.add_component(TestComponent(Rc::clone(&text)));
128        assert_eq!(components.components.len(), 1);
129
130        components.process_event_entry(
131            EventEntry::new(
132                std::time::Duration::default(),
133                comp,
134                String::from("Modified"),
135            ),
136            &mut scheduler,
137            &mut state,
138        );
139
140        assert_eq!(*text.borrow(), "Modified");
141    }
142
143    #[test]
144    fn test_rc_ref_cell() {
145        let mut scheduler = Scheduler::default();
146        let mut state = State::default();
147
148        let component = Rc::new(RefCell::new(RcTestComponent(String::from(""))));
149        let mut components = Components::default();
150        let comp: ComponentId<String> = components.add_component(Rc::clone(&component));
151
152        components.process_event_entry(
153            EventEntry::new(
154                std::time::Duration::default(),
155                comp,
156                String::from("Modified"),
157            ),
158            &mut scheduler,
159            &mut state,
160        );
161
162        assert_eq!(component.borrow().0, "Modified");
163    }
164}