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}