mmids_core/workflows/
definitions.rs

1use std::collections::hash_map::DefaultHasher;
2use std::collections::HashMap;
3use std::fmt::Formatter;
4use std::hash::{Hash, Hasher};
5
6/// Identifier representing the type of the workflow step being defined
7#[derive(Clone, Hash, Debug, Eq, PartialEq)]
8pub struct WorkflowStepType(pub String);
9
10/// The definition of a workflow step and any parameters it may be using
11#[derive(Clone, Debug)]
12pub struct WorkflowStepDefinition {
13    pub step_type: WorkflowStepType,
14    pub parameters: HashMap<String, Option<String>>,
15}
16
17/// The definition of a workflow and the steps (in order) it contains
18#[derive(Clone, Debug)]
19pub struct WorkflowDefinition {
20    pub name: String,
21    pub routed_by_reactor: bool,
22    pub steps: Vec<WorkflowStepDefinition>,
23}
24
25impl std::fmt::Display for WorkflowStepType {
26    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
27        write!(f, "{}", self.0)
28    }
29}
30
31impl WorkflowStepDefinition {
32    /// Gets an identifier for the workflow step that's based on the step's parameters.  Two
33    /// steps with the same set of parameters and values will always produce the same id within
34    /// a single run of the the application, but the identifiers are not guaranteed to be consistent
35    /// across application runs.
36    pub fn get_id(&self) -> u64 {
37        let mut hasher = DefaultHasher::new();
38        self.hash(&mut hasher);
39        hasher.finish()
40    }
41}
42
43impl Hash for WorkflowStepDefinition {
44    fn hash<H: Hasher>(&self, state: &mut H) {
45        let mut sorted_keys: Vec<&String> = self.parameters.keys().collect();
46        sorted_keys.sort();
47
48        self.step_type.hash(state);
49        for key in sorted_keys {
50            key.hash(state);
51            self.parameters.get(key).hash(state);
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn two_steps_with_identical_setups_have_same_id() {
62        let mut step1 = WorkflowStepDefinition {
63            step_type: WorkflowStepType("test".to_string()),
64            parameters: HashMap::new(),
65        };
66
67        step1
68            .parameters
69            .insert("a".to_string(), Some("b".to_string()));
70        step1
71            .parameters
72            .insert("c".to_string(), Some("d".to_string()));
73
74        let mut step2 = WorkflowStepDefinition {
75            step_type: WorkflowStepType("test".to_string()),
76            parameters: HashMap::new(),
77        };
78
79        step2
80            .parameters
81            .insert("c".to_string(), Some("d".to_string()));
82        step2
83            .parameters
84            .insert("a".to_string(), Some("b".to_string()));
85
86        assert_eq!(step1.get_id(), step2.get_id());
87    }
88
89    #[test]
90    fn two_steps_with_different_types_do_not_have_same_id() {
91        let mut step1 = WorkflowStepDefinition {
92            step_type: WorkflowStepType("test".to_string()),
93            parameters: HashMap::new(),
94        };
95
96        step1
97            .parameters
98            .insert("a".to_string(), Some("b".to_string()));
99        step1
100            .parameters
101            .insert("c".to_string(), Some("d".to_string()));
102
103        let mut step2 = WorkflowStepDefinition {
104            step_type: WorkflowStepType("test2".to_string()),
105            parameters: HashMap::new(),
106        };
107
108        step2
109            .parameters
110            .insert("c".to_string(), Some("d".to_string()));
111        step2
112            .parameters
113            .insert("a".to_string(), Some("b".to_string()));
114
115        assert_ne!(step1.get_id(), step2.get_id());
116    }
117
118    #[test]
119    fn two_steps_with_different_parameters_do_not_have_same_id() {
120        let mut step1 = WorkflowStepDefinition {
121            step_type: WorkflowStepType("test".to_string()),
122            parameters: HashMap::new(),
123        };
124
125        step1
126            .parameters
127            .insert("a".to_string(), Some("b".to_string()));
128        step1
129            .parameters
130            .insert("c".to_string(), Some("d".to_string()));
131
132        let mut step2 = WorkflowStepDefinition {
133            step_type: WorkflowStepType("test2".to_string()),
134            parameters: HashMap::new(),
135        };
136
137        step2
138            .parameters
139            .insert("c".to_string(), Some("d".to_string()));
140        step2
141            .parameters
142            .insert("a".to_string(), Some("f".to_string()));
143
144        assert_ne!(step1.get_id(), step2.get_id());
145    }
146}