1use crate::{
2 Error, IntermediateEvent, With,
3 model::{ActivityType, Boundary, GatewayType},
4};
5use std::{
6 collections::HashMap,
7 fmt::Display,
8 sync::{Arc, Mutex},
9};
10
11const FUNC_MAP_ERROR_MSG: &str = "couldn't fetch function map";
12
13pub type Data<T> = Arc<Mutex<T>>;
15
16pub type TaskResult = Option<Boundary>;
18
19type TaskCallback<T> = Box<dyn Fn(Data<T>) -> TaskResult + Sync + Send>;
20type ExclusiveCallback<T> = Box<dyn Fn(Data<T>) -> Option<&'static str> + Sync + Send>;
21type InclusiveCallback<T> = Box<dyn Fn(Data<T>) -> With + Sync + Send>;
22type EventBasedCallback<T> = Box<dyn Fn(Data<T>) -> IntermediateEvent + Sync + Send>;
23
24pub(super) struct Handler<T> {
25 task: Vec<TaskCallback<T>>,
26 exclusive: Vec<ExclusiveCallback<T>>,
27 inclusive: Vec<InclusiveCallback<T>>,
28 event_based: Vec<EventBasedCallback<T>>,
29
30 handler_map: Option<HandlerMap>,
32}
33
34impl<T> Default for Handler<T> {
35 fn default() -> Self {
36 Self {
37 task: Default::default(),
38 exclusive: Default::default(),
39 inclusive: Default::default(),
40 event_based: Default::default(),
41 handler_map: Some(Default::default()),
42 }
43 }
44}
45
46impl<T> Handler<T> {
47 pub(super) fn add_task<F>(&mut self, name: impl Into<String>, func: F)
48 where
49 F: Fn(Data<T>) -> TaskResult + 'static + Sync + Send,
50 {
51 if let Some(hm) = &mut self.handler_map {
52 hm.insert_task(name, self.task.len());
53 self.task.push(Box::new(func));
54 }
55 }
56
57 pub(super) fn add_exclusive<F>(&mut self, name: impl Into<String>, func: F)
58 where
59 F: Fn(Data<T>) -> Option<&'static str> + 'static + Sync + Send,
60 {
61 if let Some(hm) = &mut self.handler_map {
62 hm.insert_exclusive(name, self.exclusive.len());
63 self.exclusive.push(Box::new(func));
64 }
65 }
66
67 pub(super) fn add_inclusive<F>(&mut self, name: impl Into<String>, func: F)
68 where
69 F: Fn(Data<T>) -> With + 'static + Sync + Send,
70 {
71 if let Some(hm) = &mut self.handler_map {
72 hm.insert_inclusive(name, self.inclusive.len());
73 self.inclusive.push(Box::new(func));
74 }
75 }
76
77 pub(super) fn add_event_based<F>(&mut self, name: impl Into<String>, func: F)
78 where
79 F: Fn(Data<T>) -> IntermediateEvent + 'static + Sync + Send,
80 {
81 if let Some(hm) = &mut self.handler_map {
82 hm.insert_event_based(name, self.event_based.len());
83 self.event_based.push(Box::new(func));
84 }
85 }
86
87 pub(super) fn build(&mut self) -> Result<HandlerMap, Error> {
89 self.handler_map
90 .take()
91 .ok_or_else(|| Error::Builder(FUNC_MAP_ERROR_MSG.into()))
92 }
93
94 pub(super) fn run_task(&self, index: usize, data: Data<T>) -> Option<TaskResult> {
95 self.task.get(index).map(|value| (*value)(data))
96 }
97
98 pub(super) fn run_exclusive(
99 &self,
100 index: usize,
101 data: Data<T>,
102 ) -> Option<Option<&'static str>> {
103 self.exclusive.get(index).map(|value| (*value)(data))
104 }
105
106 pub(super) fn run_inclusive(&self, index: usize, data: Data<T>) -> Option<With> {
107 self.inclusive.get(index).map(|value| (*value)(data))
108 }
109
110 pub(super) fn run_event_based(&self, index: usize, data: Data<T>) -> Option<IntermediateEvent> {
111 self.event_based.get(index).map(|value| (*value)(data))
112 }
113}
114
115#[derive(Default, Debug)]
116pub(super) struct HandlerMap {
117 task: HashMap<String, usize>,
118 exclusive: HashMap<String, usize>,
119 inclusive: HashMap<String, usize>,
120 event_based: HashMap<String, usize>,
121}
122
123impl HandlerMap {
124 pub(super) fn task(&self) -> &HashMap<String, usize> {
125 &self.task
126 }
127
128 pub(super) fn exclusive(&self) -> &HashMap<String, usize> {
129 &self.exclusive
130 }
131
132 pub(super) fn inclusive(&self) -> &HashMap<String, usize> {
133 &self.inclusive
134 }
135
136 pub(super) fn event_based(&self) -> &HashMap<String, usize> {
137 &self.event_based
138 }
139
140 fn insert_task(&mut self, name: impl Into<String>, index: usize) {
141 let name = name.into();
142 if self.task.insert(name.clone(), index).is_some() {
143 warn(ActivityType::Task, name);
144 }
145 }
146
147 fn insert_exclusive(&mut self, name: impl Into<String>, index: usize) {
148 let name = name.into();
149 if self.exclusive.insert(name.clone(), index).is_some() {
150 warn(GatewayType::Exclusive, name);
151 }
152 }
153
154 fn insert_inclusive(&mut self, name: impl Into<String>, index: usize) {
155 let name = name.into();
156 if self.inclusive.insert(name.clone(), index).is_some() {
157 warn(GatewayType::Inclusive, name);
158 }
159 }
160
161 fn insert_event_based(&mut self, name: impl Into<String>, index: usize) {
162 let name = name.into();
163 if self.event_based.insert(name.clone(), index).is_some() {
164 warn(GatewayType::EventBased, name);
165 }
166 }
167}
168
169fn warn(ty: impl Display, name: impl Display) {
170 log::warn!(r#"Installed {ty} with name "{name}" multiple times"#);
171}