bacnet_server/cov/
sample.rs1use bacnet_objects::cov_change::{reports_change, same_value};
3use bacnet_types::{
4 enums::{ErrorClass, ErrorCode},
5 error::Error,
6 primitives::PropertyValue,
7};
8use std::sync::Arc;
9
10#[derive(Debug, Clone)]
13pub struct CovSample(Arc<PropertyValue>);
14impl CovSample {
15 pub fn new(value: &PropertyValue) -> Result<Self, Error> {
17 let (mut nodes, mut bytes) = (0usize, 0usize);
18 validate(value, 0, &mut nodes, &mut bytes)?;
19 Ok(Self(Arc::new(normalize(value))))
20 }
21 pub fn value(&self) -> &PropertyValue {
23 &self.0
24 }
25
26 pub(crate) fn reports(
30 &self,
31 previous: Option<&Self>,
32 increment: Option<f64>,
33 numeric: bool,
34 ) -> bool {
35 previous.is_none_or(|previous| {
36 reports_change(self.value(), previous.value(), increment, numeric)
37 })
38 }
39}
40impl PartialEq for CovSample {
41 fn eq(&self, other: &Self) -> bool {
42 same_value(self.value(), other.value())
43 }
44}
45impl Eq for CovSample {}
46fn capacity_error() -> Error {
47 Error::protocol(
48 ErrorClass::RESOURCES,
49 ErrorCode::NO_SPACE_TO_ADD_LIST_ELEMENT,
50 )
51}
52fn validate(
53 v: &PropertyValue,
54 depth: usize,
55 nodes: &mut usize,
56 bytes: &mut usize,
57) -> Result<(), Error> {
58 *nodes = nodes.checked_add(1).ok_or_else(capacity_error)?;
59 if *nodes > 1024 {
60 return Err(capacity_error());
61 }
62 use PropertyValue::*;
63 let size = match v {
64 List(values) => {
65 if depth == 32 {
66 return Err(capacity_error());
67 }
68 for value in values {
69 validate(value, depth + 1, nodes, bytes)?;
70 }
71 0
72 }
73 OctetString(v) | ApplicationData(v) => v.len(),
74 CharacterString(v) => v.len(),
75 BitString { data, .. } => data.len(),
76 Null => 0,
77 Boolean(_) => 1,
78 Real(_) | Signed(_) | Enumerated(_) | Date(_) | Time(_) | ObjectIdentifier(_) => 4,
79 Unsigned(_) | Double(_) => 8,
80 };
81 *bytes = bytes.checked_add(size).ok_or_else(capacity_error)?;
82 if *bytes > 65536 {
83 return Err(capacity_error());
84 }
85 Ok(())
86}
87fn normalize(v: &PropertyValue) -> PropertyValue {
88 use PropertyValue::*;
89 fn bytes(v: &[u8]) -> Vec<u8> {
90 v.to_vec().into_boxed_slice().into_vec()
91 }
92 match v {
93 List(v) => List(
94 v.iter()
95 .map(normalize)
96 .collect::<Vec<_>>()
97 .into_boxed_slice()
98 .into_vec(),
99 ),
100 OctetString(v) => OctetString(bytes(v)),
101 ApplicationData(v) => ApplicationData(bytes(v)),
102 CharacterString(v) => CharacterString(v.as_str().into()),
103 BitString { unused_bits, data } => BitString {
104 unused_bits: *unused_bits,
105 data: bytes(data),
106 },
107 _ => v.clone(),
108 }
109}
110
111#[cfg(test)]
112mod tests;