reactive_graph_behaviour_model_api/
fsm.rs1use reactive_graph_reactive_model_api::ReactiveInstance;
2use reactive_graph_reactive_model_api::ReactiveInstanceContainer;
3
4use crate::BehaviourState;
5use crate::BehaviourTransitionError;
6use crate::BehaviourTransitions;
7use crate::BehaviourTypeId;
8use crate::BehaviourTypesContainer;
9use crate::BehaviourValidator;
10
11pub trait BehaviourFsm<ID: Clone, T: ReactiveInstance<ID> + BehaviourTypesContainer>: ReactiveInstanceContainer<ID, T> + Send + Sync {
12 fn ty(&self) -> &BehaviourTypeId;
14
15 fn get_state(&self) -> BehaviourState;
17
18 fn set_state(&self, state: BehaviourState);
20
21 fn get_validator(&self) -> &dyn BehaviourValidator<ID, T>;
23
24 fn get_transitions(&self) -> &dyn BehaviourTransitions<ID, T>;
26
27 fn transition(&self, target_state: BehaviourState) -> Result<(), BehaviourTransitionError> {
29 match self.get_state() {
30 BehaviourState::Created => match target_state {
31 BehaviourState::Created => Err(BehaviourTransitionError::InvalidTransition),
32 BehaviourState::Valid => self
33 .get_validator()
34 .validate()
35 .map(|_| self.set_state(target_state))
36 .map_err(BehaviourTransitionError::BehaviourInvalid),
37 BehaviourState::Ready => self.transition(BehaviourState::Valid).and_then(|_| {
38 self.get_transitions()
39 .init()
40 .map(|_| self.set_state(target_state))
41 .map_err(BehaviourTransitionError::BehaviourInitializationFailed)
42 }),
43 BehaviourState::Connected => self.transition(BehaviourState::Ready).and_then(|_| {
44 self.get_transitions()
45 .connect()
46 .map(|_| self.get_reactive_instance().add_behaviour(self.ty().clone()))
47 .map(|_| self.set_state(target_state))
48 .map_err(BehaviourTransitionError::BehaviourConnectFailed)
49 }),
50 },
51 BehaviourState::Valid => match target_state {
52 BehaviourState::Created => Err(BehaviourTransitionError::InvalidTransition),
53 BehaviourState::Valid => Err(BehaviourTransitionError::InvalidTransition),
54 BehaviourState::Ready => self
55 .get_transitions()
56 .init()
57 .map(|_| self.set_state(target_state))
58 .map_err(BehaviourTransitionError::BehaviourInitializationFailed),
59 BehaviourState::Connected => self.transition(BehaviourState::Ready).and_then(|_| {
60 self.get_transitions()
61 .connect()
62 .map(|_| self.get_reactive_instance().add_behaviour(self.ty().clone()))
63 .map(|_| self.set_state(target_state))
64 .map_err(BehaviourTransitionError::BehaviourConnectFailed)
65 }),
66 },
67 BehaviourState::Ready => match target_state {
68 BehaviourState::Created => Err(BehaviourTransitionError::InvalidTransition),
69 BehaviourState::Valid => Err(BehaviourTransitionError::InvalidTransition),
70 BehaviourState::Ready => Err(BehaviourTransitionError::InvalidTransition),
71 BehaviourState::Connected => self
72 .get_transitions()
73 .connect()
74 .map(|_| self.get_reactive_instance().add_behaviour(self.ty().clone()))
75 .map(|_| self.set_state(target_state))
76 .map_err(BehaviourTransitionError::BehaviourConnectFailed),
77 },
78 BehaviourState::Connected => match target_state {
79 BehaviourState::Created => Err(BehaviourTransitionError::InvalidTransition),
80 BehaviourState::Valid => Err(BehaviourTransitionError::InvalidTransition),
81 BehaviourState::Ready => self
82 .get_transitions()
83 .disconnect()
84 .map(|_| self.get_reactive_instance().remove_behaviour(self.ty()))
85 .map(|_| self.set_state(target_state))
86 .map_err(BehaviourTransitionError::BehaviourDisconnectFailed),
87 BehaviourState::Connected => Err(BehaviourTransitionError::InvalidTransition),
88 },
89 }
90 }
91}
92
93#[macro_export]
94macro_rules! behaviour_fsm {
95 ($fsm: ident, $validator: ty, $transitions: ty, $id: ty, $reactive_instance: ty) => {
96 use reactive_graph_graph::PropertyInstanceGetter as BehaviourFsmPropertyInstanceGetter;
97
98 pub struct $fsm {
99 pub reactive_instance: $reactive_instance,
100 pub ty: $crate::BehaviourTypeId,
101 pub state: std::sync::RwLock<$crate::BehaviourState>,
102 pub validator: $validator,
103 pub transitions: $transitions,
104 }
105
106 impl $fsm {
107 pub fn new(reactive_instance: $reactive_instance, ty: $crate::BehaviourTypeId, validator: $validator, transitions: $transitions) -> Self {
108 $fsm {
109 reactive_instance,
110 ty,
111 state: std::sync::RwLock::new($crate::BehaviourState::Created),
112 validator,
113 transitions,
114 }
115 }
116 }
117
118 impl $crate::BehaviourFsm<$id, $reactive_instance> for $fsm {
119 fn ty(&self) -> &$crate::BehaviourTypeId {
120 &self.ty
121 }
122
123 fn get_state(&self) -> $crate::BehaviourState {
124 let reader = self.state.read().unwrap();
125 (*reader).clone()
126 }
127
128 fn set_state(&self, state: $crate::BehaviourState) {
129 let mut writer = self.state.write().unwrap();
130 *writer = state;
131 }
132
133 fn get_validator(&self) -> &dyn $crate::BehaviourValidator<$id, $reactive_instance> {
134 &self.validator
135 }
136
137 fn get_transitions(&self) -> &dyn $crate::BehaviourTransitions<$id, $reactive_instance> {
138 &self.transitions
139 }
140 }
141
142 impl reactive_graph_reactive_model_api::ReactiveInstanceContainer<$id, $reactive_instance> for $fsm {
143 fn get_reactive_instance(&self) -> &$reactive_instance {
144 &self.reactive_instance
145 }
146
147 fn get(&self, property_name: &str) -> Option<serde_json::Value> {
148 self.reactive_instance.get(property_name)
149 }
150
151 fn set(&self, property_name: &str, value: serde_json::Value) {
152 self.reactive_instance.set(property_name, value);
153 }
154 }
155 };
156}