1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use stepflow_base::{ObjectStoreContent, ObjectStoreFiltered, generate_id_type, IdError};
use stepflow_data::{StateData, StateDataFiltered, value::Value, var::{Var, VarId}};
use stepflow_step::{Step};
use crate::ActionError;
mod action_uri;
pub use action_uri::UriAction;
mod action_htmlform;
pub use action_htmlform::{HtmlFormAction, HtmlFormConfig};
mod action_callback;
pub use action_callback::CallbackAction;
mod action_set_data;
pub use action_set_data::SetDataAction;
generate_id_type!(ActionId);
#[derive(Debug, Clone)]
pub enum ActionResult {
StartWith(Box<dyn Value>),
Finished(StateData),
CannotFulfill,
}
impl PartialEq for ActionResult {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(ActionResult::StartWith(val), ActionResult::StartWith(val_other)) => {
val == val_other
},
(ActionResult::Finished(data), ActionResult::Finished(data_other)) => {
data == data_other
},
(ActionResult::CannotFulfill, ActionResult::CannotFulfill) => {
true
},
(ActionResult::StartWith(_), _) |
(ActionResult::Finished(_), _) |
(ActionResult::CannotFulfill, _) => {
false
},
}
}
}
pub trait Action: std::fmt::Debug {
fn id(&self) -> &ActionId;
fn boxed(self) -> Box<dyn Action + Sync + Send>;
fn start(&mut self, step: &Step, step_name: Option<&str>, step_data: &StateDataFiltered, vars: &ObjectStoreFiltered<Box<dyn Var + Send + Sync>, VarId>)
-> Result<ActionResult, ActionError>;
}
impl ObjectStoreContent for Box<dyn Action + Sync + Send> {
type IdType = ActionId;
fn new_id(id_val: u32) -> Self::IdType {
ActionId::new(id_val)
}
fn id(&self) -> &Self::IdType {
self.as_ref().id()
}
}
#[cfg(test)]
pub fn test_action_setup<'a>() -> (Step, StateData, stepflow_base::ObjectStore<Box<dyn Var + Send + Sync>, VarId>, VarId, Box<dyn stepflow_data::value::Value>) {
let mut var_store: stepflow_base::ObjectStore<Box<dyn Var + Send + Sync>, VarId> = stepflow_base::ObjectStore::new();
let var_id = var_store.insert_new(|id| Ok(stepflow_data::var::StringVar::new(id).boxed())).unwrap();
let var = var_store.get(&var_id).unwrap();
let state_val = stepflow_data::value::StringValue::try_new("hi").unwrap().boxed();
let mut state_data = StateData::new();
state_data.insert(var, state_val.clone()).unwrap();
let step = Step::new(stepflow_step::StepId::new(2), None, vec![]);
(step, state_data, var_store, var_id, state_val)
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use stepflow_test_util::test_id;
use stepflow_data::{StateData, value::TrueValue};
use crate::{Action, ActionId};
use super::{ActionResult, UriAction};
#[test]
fn eq() {
let result_start = ActionResult::StartWith(TrueValue::new().boxed());
let result_finish = ActionResult::Finished(StateData::new());
let result_cannot = ActionResult::CannotFulfill;
assert_eq!(result_start, result_start);
assert_ne!(result_start, result_finish);
assert_ne!(result_start, result_cannot);
assert_eq!(result_finish, result_finish);
assert_ne!(result_finish, result_cannot);
}
#[test]
fn object_store_content() {
let test_action = UriAction::new(test_id!(ActionId), http::Uri::try_from("test").unwrap());
let test_action_id = test_action.id().clone();
let boxed: Box<dyn Action> = test_action.boxed();
let boxed_id = boxed.id().clone();
assert_eq!(test_action_id, boxed_id);
}
}