reactive_graph_behaviour_model_api/
fsm.rs

1use 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    /// Returns the current state of the behaviour.
13    fn ty(&self) -> &BehaviourTypeId;
14
15    /// Returns the current state of the behaviour.
16    fn get_state(&self) -> BehaviourState;
17
18    /// Returns the current state of the behaviour.
19    fn set_state(&self, state: BehaviourState);
20
21    /// Returns the validator.
22    fn get_validator(&self) -> &dyn BehaviourValidator<ID, T>;
23
24    /// Returns the validator.
25    fn get_transitions(&self) -> &dyn BehaviourTransitions<ID, T>;
26
27    /// Executes a behaviour transition.
28    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}