reactive_graph_std_numeric/behaviour/entity/operation/
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::Value;
7use serde_json::json;
8use uuid::Uuid;
9
10use reactive_graph_std_numeric_model::NumericOperationProperties::LHS;
11use reactive_graph_std_result_model::ResultNumberF64Properties::RESULT;
12
13use crate::behaviour::as_f64;
14use crate::behaviour::entity::operation::function::NumericOperationF64Function;
15
16entity_behaviour!(
17    NumericOperationF64,
18    NumericOperationF64Factory,
19    NumericOperationF64Fsm,
20    NumericOperationF64BehaviourTransitions,
21    NumericOperationF64Validator,
22    f,
23    NumericOperationF64Function
24);
25
26behaviour_validator!(NumericOperationF64Validator, Uuid, ReactiveEntity, LHS.as_ref(), RESULT.as_ref());
27
28impl BehaviourInit<Uuid, ReactiveEntity> for NumericOperationF64BehaviourTransitions {
29    fn init(&self) -> Result<(), BehaviourInitializationFailed> {
30        let lhs = self.reactive_instance.get(LHS).and_then(as_f64).ok_or(BehaviourInitializationFailed {})?;
31        let f = self.f;
32        let initial_value = f(lhs);
33        self.reactive_instance.set(RESULT, json!(initial_value));
34        Ok(())
35    }
36}
37
38impl BehaviourConnect<Uuid, ReactiveEntity> for NumericOperationF64BehaviourTransitions {
39    fn connect(&self) -> Result<(), BehaviourConnectFailed> {
40        let reactive_instance = self.property_observers.reactive_instance.clone();
41        let f = self.f;
42        self.property_observers.observe_with_handle(LHS.as_ref(), move |v: &Value| {
43            if let Some(v) = as_f64(v.clone()) {
44                reactive_instance.set(RESULT, json!(f(v)));
45            }
46        });
47        Ok(())
48    }
49}
50
51impl BehaviourShutdown<Uuid, ReactiveEntity> for NumericOperationF64BehaviourTransitions {}
52impl BehaviourTransitions<Uuid, ReactiveEntity> for NumericOperationF64BehaviourTransitions {}
53
54#[cfg(test)]
55mod tests {
56    use std::sync::Arc;
57
58    use reactive_graph_behaviour_model_api::BehaviourFactory;
59    use reactive_graph_behaviour_model_api::BehaviourFsm;
60    use reactive_graph_behaviour_model_api::BehaviourTypeId;
61    use reactive_graph_graph::prelude::*;
62    use reactive_graph_reactive_model_impl::ReactiveEntity;
63    use uuid::Uuid;
64
65    use reactive_graph_std_numeric_model::NumericOperationF64;
66
67    use crate::behaviour::entity::operation::behaviour_f64::NumericOperationF64Factory;
68    use crate::behaviour::entity::operation::function::*;
69    use crate::behaviour::entity::operation::tests::numeric_operation;
70
71    #[test]
72    fn numeric_operation_behaviour_test() {
73        let nv: f64 = -0.5;
74        let nz: f64 = -0.0;
75        let pz: f64 = 0.0;
76        let pv: f64 = 0.5;
77
78        for (behaviour_ty, f) in NUMERIC_OPERATIONS_F64.iter() {
79            let entity_ty = EntityTypeId::new_from_type(behaviour_ty.namespace(), behaviour_ty.type_name());
80
81            // negative
82            let expected = f(nv);
83            let result = test_numeric_operation_behaviour(behaviour_ty, &entity_ty, nv);
84            println!("{}({})  |  {:?}  |  {:?}", entity_ty, nv, expected, result);
85            if !expected.is_nan() {
86                assert_eq!(expected, result.unwrap());
87            } else {
88                assert!(result.is_none());
89            }
90
91            // negative zero
92            let expected = f(nz);
93            let result = test_numeric_operation_behaviour(behaviour_ty, &entity_ty, nz);
94            println!("{}({})  |  {:?}  |  {:?}", entity_ty, nz, expected, result);
95            if !expected.is_infinite() {
96                assert_eq!(expected, result.unwrap());
97            } else {
98                assert!(result.is_none());
99            }
100
101            // positive zero
102            let expected = f(pz);
103            let result = test_numeric_operation_behaviour(behaviour_ty, &entity_ty, pz);
104            println!("{}({})  |  {:?}  |  {:?}", entity_ty, pz, expected, result);
105            if !expected.is_infinite() {
106                assert_eq!(expected, result.unwrap());
107            } else {
108                assert!(result.is_none());
109            }
110
111            // positive
112            let expected = f(pv);
113            let result = test_numeric_operation_behaviour(behaviour_ty, &entity_ty, pv);
114            println!("{}({})  |  {:?}  |  {:?}", entity_ty, pv, expected, result);
115            assert_eq!(expected, result.unwrap());
116        }
117    }
118
119    fn test_numeric_operation_behaviour(behaviour_ty: &BehaviourTypeId, entity_ty: &EntityTypeId, v: f64) -> Option<f64> {
120        let behaviour = create_numeric_operation_behaviour(behaviour_ty, entity_ty);
121        let reactive_instance = behaviour.get_reactive_instance();
122        let numeric_operation = NumericOperationF64::from(reactive_instance.clone());
123        numeric_operation.lhs(v);
124        numeric_operation.result()
125    }
126
127    fn create_numeric_operation_behaviour(
128        behaviour_ty: &BehaviourTypeId,
129        entity_ty: &EntityTypeId,
130    ) -> Arc<dyn BehaviourFsm<Uuid, ReactiveEntity> + Send + Sync> {
131        let reactive_instance = numeric_operation(entity_ty);
132        let not_function = NUMERIC_OPERATIONS_F64.get(&behaviour_ty).expect("Failed to get function");
133        let not_factory = NumericOperationF64Factory::new(behaviour_ty.clone(), not_function.clone());
134        not_factory.create(reactive_instance.clone()).expect("Failed to create behaviour")
135    }
136}