Skip to main content

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,
14/// Value_Source_Array and Last_Command_Time are present only under
15/// [`Commandable`](Self::Commandable). Value_Source is too, unless the object
16/// tracks the source of its noncommandable Present_Value (`set_value_source_tracking`
17/// on each Value object, #1552).
18/// Under every access, Out_Of_Service TRUE keeps the local application from
19/// changing Present_Value and lets peers write it for testing (Clause 12,
20/// Out_Of_Service of each Value object).
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22pub enum PresentValueAccess {
23    /// The application sets Present_Value. Peers write it only while
24    /// Out_Of_Service is TRUE.
25    ReadOnly,
26    /// A peer write replaces Present_Value, and so does the application.
27    Writable,
28    /// Peer writes go through Priority_Array, and the highest occupied
29    /// priority is Present_Value (Clause 19.2).
30    #[default]
31    Commandable,
32}
33
34impl PresentValueAccess {
35    /// Whether a row with this presence condition exists under this access.
36    /// `source_tracked` says whether a noncommandable object tracks its
37    /// Present_Value's source, which keeps its Value_Source row.
38    pub(crate) fn includes(
39        self,
40        condition: Option<PropertyPresenceCondition>,
41        source_tracked: bool,
42    ) -> bool {
43        use PropertyPresenceCondition as C;
44        self == Self::Commandable
45            || match condition {
46                Some(
47                    C::Commandable
48                    | C::CommandableAuditReporting
49                    | C::CommandableValueSourceTracking,
50                ) => false,
51                Some(C::ValueSourceTracking) => source_tracked,
52                _ => true,
53            }
54    }
55
56    /// `rows` as this access presents them: the rows it excludes removed, and
57    /// Present_Value's write capability set to match.
58    pub(crate) fn project(
59        self,
60        rows: Cow<'_, [PropertyMetadata]>,
61        source_tracked: bool,
62    ) -> Cow<'_, [PropertyMetadata]> {
63        let present_value = match self {
64            Self::Commandable => return rows,
65            Self::Writable => PropertyWriteCapability::Always,
66            Self::ReadOnly => PropertyWriteCapability::WhenOutOfService,
67        };
68
69        Cow::Owned(
70            rows.iter()
71                .filter(|row| self.includes(row.presence_condition, source_tracked))
72                .map(|row| {
73                    if row.property_identifier == PropertyIdentifier::PRESENT_VALUE {
74                        PropertyMetadata::new(
75                            row.property_identifier,
76                            row.conformance,
77                            row.presence_condition,
78                            present_value,
79                        )
80                    } else {
81                        *row
82                    }
83                })
84                .collect(),
85        )
86    }
87
88    /// Whether `rows` hold `property` under a condition this access excludes.
89    pub(crate) fn excludes(
90        self,
91        rows: &[PropertyMetadata],
92        property: PropertyIdentifier,
93        source_tracked: bool,
94    ) -> bool {
95        self != Self::Commandable
96            && rows.iter().any(|row| {
97                row.property_identifier == property
98                    && !self.includes(row.presence_condition, source_tracked)
99            })
100    }
101}