snurr/process/
handler.rs

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
13/// Generic type for the task and gateway inputs.
14pub type Data<T> = Arc<Mutex<T>>;
15
16/// Task result type
17pub 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    // Used while building. Is None after use.
31    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    // Consumes the handler_map and cannot add more things with add_
88    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}