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
10pub trait Component: ProcessEventEntry {
12 type Event: fmt::Debug + 'static;
14
15 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#[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 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 #[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}