reactive_graph_std_state/behaviour/component/state/
mod.rs

1use std::sync::Arc;
2use std::sync::LazyLock;
3
4use reactive_graph_behaviour_model_api::behaviour_validator;
5use reactive_graph_behaviour_model_api::prelude::*;
6use reactive_graph_behaviour_model_impl::entity::EntityBehaviourFactories;
7use reactive_graph_behaviour_model_impl::entity_behaviour;
8use reactive_graph_graph::prelude::*;
9use reactive_graph_reactive_model_api::ReactiveInstanceContainer;
10use reactive_graph_reactive_model_impl::ReactiveEntity;
11use serde_json::Value;
12use uuid::Uuid;
13
14use reactive_graph_std_state_model::NAMESPACE_STATE;
15
16use crate::model_state::StateProperties;
17use crate::model_value::*;
18
19pub static STATE_BEHAVIOURS: LazyLock<BehaviourTypeIds> = LazyLock::new(|| {
20    BehaviourTypeIds::with_namespace(NAMESPACE_STATE)
21        .ty("state_array")
22        .ty("state_boolean")
23        .ty("state_number")
24        .ty("state_object")
25        .ty("state_string")
26        .into()
27});
28
29pub static STATE_FACTORIES: LazyLock<EntityBehaviourFactories> = LazyLock::new(|| {
30    STATE_BEHAVIOURS.iter().fold(EntityBehaviourFactories::new(), |factories, behaviour_ty| {
31        factories.factory(Arc::new(StateFactory::new(behaviour_ty.clone())))
32    })
33});
34
35entity_behaviour!(State, StateFactory, StateFsm, StateBehaviourTransitions, StateValidator);
36
37behaviour_validator!(
38    StateValidator,
39    Uuid,
40    ReactiveEntity,
41    StateProperties::STATE.as_ref(),
42    StateProperties::SET_STATE.as_ref(),
43    ValueProperties::VALUE.as_ref()
44);
45
46impl BehaviourInit<Uuid, ReactiveEntity> for StateBehaviourTransitions {
47    fn init(&self) -> Result<(), BehaviourInitializationFailed> {
48        // If value and state are not equal propagate the state, initially
49        let state = self.get(StateProperties::STATE.as_ref()).ok_or(BehaviourInitializationFailed {})?;
50        let value = self.get(ValueProperties::VALUE.as_ref()).ok_or(BehaviourInitializationFailed {})?;
51        if state != value {
52            self.set(ValueProperties::VALUE.as_ref(), state);
53        }
54        Ok(())
55    }
56}
57
58impl BehaviourShutdown<Uuid, ReactiveEntity> for StateBehaviourTransitions {}
59
60impl BehaviourConnect<Uuid, ReactiveEntity> for StateBehaviourTransitions {
61    fn connect(&self) -> Result<(), BehaviourConnectFailed> {
62        let reactive_instance = self.property_observers.reactive_instance.clone();
63        self.property_observers
64            .observe_with_handle(StateProperties::SET_STATE.as_ref(), move |new_value: &Value| {
65                if let Some(old_value) = reactive_instance.get(StateProperties::STATE.as_ref()) {
66                    let new_value = new_value.clone();
67                    if old_value != new_value {
68                        reactive_instance.set(StateProperties::STATE.as_ref(), new_value);
69                    }
70                }
71            });
72        // Propagate state -> value
73        let reactive_instance = self.property_observers.reactive_instance.clone();
74        self.property_observers.observe_with_handle(StateProperties::STATE.as_ref(), move |v: &Value| {
75            reactive_instance.set(ValueProperties::VALUE.as_ref(), v.clone());
76        });
77        Ok(())
78    }
79}
80
81impl BehaviourTransitions<Uuid, ReactiveEntity> for StateBehaviourTransitions {}