bacnet_objects/present_value_access.rs
1//! How a Value object's Present_Value is written.
2
3use std::borrow::Cow;
4
5use bacnet_types::enums::PropertyIdentifier;
6
7use crate::property_metadata::{
8 PropertyMetadata, PropertyPresenceCondition, PropertyWriteCapability,
9};
10
11/// How peers and the local application write a Value object's Present_Value.
12///
13/// Priority_Array, Relinquish_Default, Current_Command_Priority and the
14/// command-source properties are present only under [`Commandable`](Self::Commandable).
15/// Under every access, Out_Of_Service TRUE keeps the local application from
16/// changing Present_Value and lets peers write it for testing (Clause 12,
17/// Out_Of_Service of each Value object).
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
19pub enum PresentValueAccess {
20 /// The application sets Present_Value. Peers write it only while
21 /// Out_Of_Service is TRUE.
22 ReadOnly,
23 /// A peer write replaces Present_Value, and so does the application.
24 Writable,
25 /// Peer writes go through Priority_Array, and the highest occupied
26 /// priority is Present_Value (Clause 19.2).
27 #[default]
28 Commandable,
29}
30
31impl PresentValueAccess {
32 /// Whether a row with this presence condition exists under this access.
33 pub(crate) fn includes(self, condition: Option<PropertyPresenceCondition>) -> bool {
34 self == Self::Commandable
35 || !matches!(
36 condition,
37 Some(
38 PropertyPresenceCondition::Commandable
39 | PropertyPresenceCondition::CommandableAuditReporting
40 | PropertyPresenceCondition::ValueSourceTracking
41 | PropertyPresenceCondition::CommandableValueSourceTracking
42 )
43 )
44 }
45
46 /// `rows` as this access presents them: the rows it excludes removed, and
47 /// Present_Value's write capability set to match.
48 pub(crate) fn project(self, rows: Cow<'_, [PropertyMetadata]>) -> Cow<'_, [PropertyMetadata]> {
49 let present_value = match self {
50 Self::Commandable => return rows,
51 Self::Writable => PropertyWriteCapability::Always,
52 Self::ReadOnly => PropertyWriteCapability::WhenOutOfService,
53 };
54
55 Cow::Owned(
56 rows.iter()
57 .filter(|row| self.includes(row.presence_condition))
58 .map(|row| {
59 if row.property_identifier == PropertyIdentifier::PRESENT_VALUE {
60 PropertyMetadata::new(
61 row.property_identifier,
62 row.conformance,
63 row.presence_condition,
64 present_value,
65 )
66 } else {
67 *row
68 }
69 })
70 .collect(),
71 )
72 }
73
74 /// Whether `rows` hold `property` under a condition this access excludes.
75 pub(crate) fn excludes(self, rows: &[PropertyMetadata], property: PropertyIdentifier) -> bool {
76 self != Self::Commandable
77 && rows.iter().any(|row| {
78 row.property_identifier == property && !self.includes(row.presence_condition)
79 })
80 }
81}