bacnet_objects/
cov_change.rs1use bacnet_types::enums::PropertyIdentifier;
12use bacnet_types::primitives::PropertyValue;
13
14use crate::traits::BACnetObject;
15
16pub fn is_numeric(
20 object: &dyn BACnetObject,
21 property: PropertyIdentifier,
22 index: Option<u32>,
23 value: &PropertyValue,
24) -> bool {
25 let array = object.is_array_property(property);
26 !(array && (index.is_none() || index == Some(0)))
27 && matches!(
28 value,
29 PropertyValue::Real(_)
30 | PropertyValue::Double(_)
31 | PropertyValue::Signed(_)
32 | PropertyValue::Unsigned(_)
33 )
34}
35
36pub fn effective_increment(
43 object: &dyn BACnetObject,
44 property: PropertyIdentifier,
45 numeric: bool,
46 explicit: Option<f32>,
47) -> Option<f64> {
48 let explicit = explicit.map(f64::from);
49 if numeric && property == PropertyIdentifier::PRESENT_VALUE {
50 explicit.or_else(|| object.cov_increment())
51 } else {
52 explicit
53 }
54}
55
56pub fn reports_change(
61 current: &PropertyValue,
62 previous: &PropertyValue,
63 increment: Option<f64>,
64 numeric: bool,
65) -> bool {
66 if !numeric {
67 return !same_value(current, previous);
68 }
69 use PropertyValue::*;
70 match (current, previous) {
71 (Unsigned(a), Unsigned(b)) => integer_delta(a.abs_diff(*b), increment),
72 (Signed(a), Signed(b)) => integer_delta(u64::from(a.abs_diff(*b)), increment),
73 (Real(a), Real(b)) => {
74 if !a.is_finite() || !b.is_finite() {
75 a.to_bits() != b.to_bits()
76 } else {
77 float_delta((f64::from(*a) - f64::from(*b)).abs(), increment)
78 }
79 }
80 (Double(a), Double(b)) => {
81 if !a.is_finite() || !b.is_finite() {
82 a.to_bits() != b.to_bits()
83 } else {
84 float_delta((a - b).abs(), increment)
85 }
86 }
87 _ => !same_value(current, previous),
88 }
89}
90
91pub fn same_value(a: &PropertyValue, b: &PropertyValue) -> bool {
95 use PropertyValue::*;
96 match (a, b) {
97 (Real(a), Real(b)) => a.to_bits() == b.to_bits(),
98 (Double(a), Double(b)) => a.to_bits() == b.to_bits(),
99 (List(a), List(b)) => a.len() == b.len() && a.iter().zip(b).all(|(a, b)| same_value(a, b)),
100 _ => a == b,
101 }
102}
103
104fn integer_delta(delta: u64, increment: Option<f64>) -> bool {
105 match increment {
106 None => delta != 0,
107 Some(i) if i <= 0.0 => delta != 0,
108 Some(i) if i.is_nan() || i >= 18_446_744_073_709_551_616.0 => false,
109 Some(i) => delta >= crate::float::ceil(i) as u64,
110 }
111}
112
113fn float_delta(delta: f64, increment: Option<f64>) -> bool {
114 match increment {
115 None => delta != 0.0,
116 Some(i) if i <= 0.0 => delta != 0.0,
117 Some(i) if !i.is_finite() => false,
118 Some(i) => delta >= i,
119 }
120}