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_string_template;
pub use action_string_template::StringTemplateAction;
mod action_htmlform;
pub use action_htmlform::{HtmlFormAction, HtmlFormConfig};
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 + stepflow_base::as_any::AsAny {
fn id(&self) -> &ActionId;
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 dyn Action + Send + Sync {
pub fn downcast<T>(&self) -> Option<&T>
where T: Action + std::any::Any
{
self.as_any().downcast_ref::<T>()
}
pub fn is<T>(&self) -> bool
where T: Action + std::any::Any
{
self.as_any().is::<T>()
}
}
impl ObjectStoreContent for Box<dyn Action + Sync + Send> {
type IdType = ActionId;
fn new_id(id_val: u16) -> 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 stepflow_test_util::test_id;
use stepflow_data::{StateData, value::TrueValue};
use super::{ActionId, HtmlFormAction, SetDataAction, ActionResult};
#[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 downcast() {
let action = HtmlFormAction::new(test_id!(ActionId), Default::default()).boxed();
assert!(action.is::<HtmlFormAction>());
assert!(!action.is::<SetDataAction>());
}
}