reactive_graph_std_arithmetic/behaviour/entity/gate/
behaviour_f64.rs

1use reactive_graph_behaviour_model_api::behaviour_validator;
2use reactive_graph_behaviour_model_api::prelude::*;
3use reactive_graph_behaviour_model_impl::entity_behaviour;
4use reactive_graph_graph::prelude::*;
5use reactive_graph_reactive_model_impl::ReactiveEntity;
6use serde_json::json;
7use uuid::Uuid;
8
9use reactive_graph_std_arithmetic_model::ArithmeticGateProperties::LHS;
10use reactive_graph_std_arithmetic_model::ArithmeticGateProperties::RESULT;
11use reactive_graph_std_arithmetic_model::ArithmeticGateProperties::RHS;
12
13use crate::behaviour::as_f64;
14use crate::behaviour::entity::gate::function::ArithmeticGateF64Function;
15
16entity_behaviour!(
17    ArithmeticGateF64,
18    ArithmeticGateF64Factory,
19    ArithmeticGateF64Fsm,
20    ArithmeticGateF64BehaviourTransitions,
21    ArithmeticGateF64Validator,
22    f,
23    ArithmeticGateF64Function
24);
25
26behaviour_validator!(ArithmeticGateF64Validator, Uuid, ReactiveEntity, LHS.as_ref(), RHS.as_ref(), RESULT.as_ref());
27
28impl BehaviourInit<Uuid, ReactiveEntity> for ArithmeticGateF64BehaviourTransitions {
29    fn init(&self) -> Result<(), BehaviourInitializationFailed> {
30        let lhs = self.reactive_instance.get(LHS).and_then(as_f64).ok_or(BehaviourInitializationFailed {})?;
31        let rhs = self.reactive_instance.get(RHS).and_then(as_f64).ok_or(BehaviourInitializationFailed {})?;
32        let f = self.f;
33        let r = f(lhs, rhs);
34        self.reactive_instance.set(RESULT, json!(r));
35        Ok(())
36    }
37}
38
39impl BehaviourConnect<Uuid, ReactiveEntity> for ArithmeticGateF64BehaviourTransitions {
40    fn connect(&self) -> Result<(), BehaviourConnectFailed> {
41        let reactive_instance = self.reactive_instance.clone();
42        let f = self.f;
43        self.property_observers.observe_with_handle(LHS.as_ref(), move |v| {
44            if let Some(lhs) = v.as_f64() {
45                if let Some(rhs) = reactive_instance.get(RHS).and_then(as_f64) {
46                    reactive_instance.set(RESULT, json!(f(lhs, rhs)));
47                }
48            }
49        });
50        let reactive_instance = self.reactive_instance.clone();
51        let f = self.f;
52        self.property_observers.observe_with_handle(RHS.as_ref(), move |v| {
53            if let Some(rhs) = v.as_f64() {
54                if let Some(lhs) = reactive_instance.get(LHS).and_then(as_f64) {
55                    reactive_instance.set(RESULT, json!(f(lhs, rhs)));
56                }
57            }
58        });
59
60        Ok(())
61    }
62}
63impl BehaviourShutdown<Uuid, ReactiveEntity> for ArithmeticGateF64BehaviourTransitions {}
64impl BehaviourTransitions<Uuid, ReactiveEntity> for ArithmeticGateF64BehaviourTransitions {}
65
66#[cfg(test)]
67mod tests {
68    use std::sync::Arc;
69
70    use reactive_graph_behaviour_model_api::prelude::*;
71    use reactive_graph_graph::prelude::*;
72    use reactive_graph_reactive_model_api::ReactiveInstanceContainer;
73    use reactive_graph_reactive_model_impl::ReactiveEntity;
74    use reactive_graph_reactive_model_impl::ReactiveProperties;
75    use serde_json::json;
76    use uuid::Uuid;
77
78    use reactive_graph_std_arithmetic_model::ArithmeticGateProperties;
79    use reactive_graph_std_arithmetic_model::NAMESPACE_ARITHMETIC_F64;
80
81    use crate::behaviour::entity::gate::behaviour_f64::ArithmeticGateF64;
82    use crate::behaviour::entity::gate::function::*;
83
84    const LHS: ArithmeticGateProperties = ArithmeticGateProperties::LHS;
85    const RHS: ArithmeticGateProperties = ArithmeticGateProperties::RHS;
86    const RESULT: ArithmeticGateProperties = ArithmeticGateProperties::RESULT;
87
88    #[test]
89    fn arithmetic_gate_f64_behaviour_test() {
90        let lhs: f64 = 0.5;
91        let rhs: f64 = 0.5;
92
93        let v = test_arithmetic_gate_f64_behaviour("add", FN_ADD_F64, lhs, rhs);
94        assert_eq!(lhs + rhs, v);
95        let v = test_arithmetic_gate_f64_behaviour("div", FN_DIV_F64, lhs, rhs);
96        assert_eq!(lhs / rhs, v);
97        let v = test_arithmetic_gate_f64_behaviour("max", FN_MAX_F64, lhs, rhs);
98        assert_eq!(lhs.min(rhs), v);
99        let v = test_arithmetic_gate_f64_behaviour("min", FN_MIN_F64, lhs, rhs);
100        assert_eq!(lhs.max(rhs), v);
101        let v = test_arithmetic_gate_f64_behaviour("mod", FN_MOD_F64, lhs, rhs);
102        assert_eq!(lhs % rhs, v);
103        let v = test_arithmetic_gate_f64_behaviour("mul", FN_MUL_F64, lhs, rhs);
104        assert_eq!(lhs * rhs, v);
105        let v = test_arithmetic_gate_f64_behaviour("sub", FN_SUB_F64, lhs, rhs);
106        assert_eq!(lhs - rhs, v);
107    }
108
109    fn test_arithmetic_gate_f64_behaviour(type_name: &str, f: ArithmeticGateFunction<f64>, lhs: f64, rhs: f64) -> f64 {
110        let ty = EntityTypeId::new_from_type(NAMESPACE_ARITHMETIC_F64, type_name);
111        let behaviour = create_arithmetic_gate_f64_behaviour(ty, f).unwrap();
112        let reactive_instance = behaviour.get_reactive_instance();
113        let arithmetic_gate = reactive_graph_std_arithmetic_model::ArithmeticGateF64::from(reactive_instance.clone());
114        arithmetic_gate.lhs(lhs);
115        arithmetic_gate.rhs(rhs);
116        arithmetic_gate.result().expect("Result is not of type f64")
117    }
118
119    fn create_arithmetic_gate_f64_behaviour(ty: EntityTypeId, f: ArithmeticGateFunction<f64>) -> Result<Arc<ArithmeticGateF64>, BehaviourCreationError> {
120        let behaviour_ty = BehaviourTypeId::from(NamespacedType::from(&ty));
121        ArithmeticGateF64::new(create_arithmetic_gate_f64_entity(ty.clone()), behaviour_ty, f)
122    }
123
124    fn create_arithmetic_gate_f64_entity(ty: EntityTypeId) -> ReactiveEntity {
125        let id = Uuid::new_v4();
126        let properties = PropertyInstances::new()
127            .property(LHS, json!(0.0))
128            .property(RHS.as_ref(), json!(0.0))
129            .property(RESULT, json!(0.0));
130        ReactiveEntity::builder()
131            .ty(ty)
132            .id(id)
133            .properties(ReactiveProperties::new_with_id_from_properties(id, properties))
134            .build()
135    }
136}