Skip to main content

bacnet_types/constructed/
read_access.rs

1//! `BACnetPropertyReference` and `ReadAccessSpecification` (Clause 21): the
2//! object and properties a ReadPropertyMultiple request names, and the
3//! element of a Group object's List_Of_Group_Members (Clause 12.14.5).
4
5#[cfg(not(feature = "std"))]
6use alloc::vec::Vec;
7
8use super::AuditPropertyReference;
9use crate::enums::PropertyIdentifier;
10use crate::error::Error;
11use crate::primitives::ObjectIdentifier;
12
13/// One property of an object, whole or one array element
14/// (`BACnetPropertyReference`, Clause 21).
15///
16/// On the wire the property identifier is context tag `[0]` and the optional
17/// Unsigned array index `[1]`. The codec is
18/// `bacnet_encoding::constructed::{encode_property_reference,
19/// decode_property_reference}`.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct PropertyReference {
22    /// Property being referred to.
23    pub property_identifier: PropertyIdentifier,
24    /// Array element index; `None` refers to the whole property.
25    pub property_array_index: Option<u32>,
26}
27
28/// An object and the properties of it to read (`ReadAccessSpecification`,
29/// Clause 21).
30///
31/// On the wire the object identifier is context tag `[0]`, followed by the
32/// property references back to back inside an opening/closing tag pair
33/// `[1]`. The codec is
34/// `bacnet_encoding::constructed::{encode_read_access_specification,
35/// decode_read_access_specification}`.
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct ReadAccessSpecification {
38    /// Object to read from.
39    pub object_identifier: ObjectIdentifier,
40    /// Properties to read from that object; may name the special ALL, REQUIRED or OPTIONAL
41    /// selectors.
42    pub list_of_property_references: Vec<PropertyReference>,
43}
44
45/// [`PropertyReference`] narrows the optional array index to `u32`, while
46/// Clause 21 leaves it an unconstrained Unsigned, so the Audit form keeps
47/// every value the primitive layer supports and converting back can fail.
48impl From<PropertyReference> for AuditPropertyReference {
49    fn from(value: PropertyReference) -> Self {
50        Self {
51            property_identifier: value.property_identifier,
52            property_array_index: value.property_array_index.map(u64::from),
53        }
54    }
55}
56
57impl TryFrom<AuditPropertyReference> for PropertyReference {
58    type Error = Error;
59
60    fn try_from(value: AuditPropertyReference) -> Result<Self, Self::Error> {
61        Ok(Self {
62            property_identifier: value.property_identifier,
63            property_array_index: value
64                .property_array_index
65                .map(u32::try_from)
66                .transpose()
67                .map_err(|_| {
68                    Error::OutOfRange(
69                        "Audit property-array-index exceeds shared PropertyReference u32 limit"
70                            .into(),
71                    )
72                })?,
73        })
74    }
75}