Skip to main content

bacnet_objects/access_control/
user.rs

1use super::*;
2
3// AccessUserObject (type 35)
4// ---------------------------------------------------------------------------
5
6/// BACnet Access User object (type 35).
7///
8/// Stands for whoever or whatever is granted access (someone, a team, a
9/// tracked item) and the credentials it holds. Its kind lives in User_Type;
10/// Table 12-38 has no Present_Value, Assigned_Access_Rights or Out_Of_Service
11/// row, so the object serves none of them (#1064).
12///
13/// Credentials, Members and Member_Of are lists of
14/// `BACnetDeviceObjectReference` (Clauses 12.33.12 to 12.33.14; #1394), so an
15/// entry may name an object in another device. Credentials names the user's
16/// Access Credential objects. Members and Member_Of name other Access Users,
17/// one level down and one level up a hierarchy of users (a department and
18/// the people in it, say). The application sets all three; they are
19/// read-only over the network.
20pub struct AccessUserObject {
21    oid: ObjectIdentifier,
22    name: String,
23    description: String,
24    user_type: AccessUserType,
25    credentials: Vec<BACnetDeviceObjectReference>,
26    members: Vec<BACnetDeviceObjectReference>,
27    member_of: Vec<BACnetDeviceObjectReference>,
28    status_flags: StatusFlags,
29    reliability: Reliability,
30}
31
32impl AccessUserObject {
33    /// Create a new Access User object.
34    pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
35        let oid = ObjectIdentifier::new(ObjectType::ACCESS_USER, instance)?;
36        Ok(Self {
37            oid,
38            name: name.into(),
39            description: String::new(),
40            user_type: AccessUserType::ASSET,
41            credentials: Vec::new(),
42            members: Vec::new(),
43            member_of: Vec::new(),
44            status_flags: StatusFlags::empty(),
45            reliability: Reliability::NO_FAULT_DETECTED,
46        })
47    }
48
49    /// Set Credentials, the Access Credential objects the user holds
50    /// (Clause 12.33.14). A reference with no device identifier names an
51    /// object in this device.
52    ///
53    /// Each reference has to name an Access Credential object, and its
54    /// device identifier, when given, a Device object; a list breaking either
55    /// rule is refused with VALUE_OUT_OF_RANGE and the credentials set before
56    /// are kept. The list is read-only over the network.
57    pub fn set_credentials(
58        &mut self,
59        credentials: impl IntoIterator<Item = impl Into<BACnetDeviceObjectReference>>,
60    ) -> Result<(), Error> {
61        self.credentials = references_to(ObjectType::ACCESS_CREDENTIAL, credentials)?;
62        Ok(())
63    }
64
65    /// Set Members, the Access Users one level below this one
66    /// (Clause 12.33.12), with the checks [`Self::set_credentials`] makes,
67    /// for Access User objects.
68    pub fn set_members(
69        &mut self,
70        members: impl IntoIterator<Item = impl Into<BACnetDeviceObjectReference>>,
71    ) -> Result<(), Error> {
72        self.members = references_to(ObjectType::ACCESS_USER, members)?;
73        Ok(())
74    }
75
76    /// Set Member_Of, the Access Users one level above this one
77    /// (Clause 12.33.13), with the checks [`Self::set_members`] makes.
78    pub fn set_member_of(
79        &mut self,
80        groups: impl IntoIterator<Item = impl Into<BACnetDeviceObjectReference>>,
81    ) -> Result<(), Error> {
82        self.member_of = references_to(ObjectType::ACCESS_USER, groups)?;
83        Ok(())
84    }
85}
86
87impl BACnetObject for AccessUserObject {
88    fn object_identifier(&self) -> ObjectIdentifier {
89        self.oid
90    }
91
92    fn object_name(&self) -> &str {
93        &self.name
94    }
95
96    fn read_property(
97        &self,
98        property: PropertyIdentifier,
99        array_index: Option<u32>,
100    ) -> Result<PropertyValue, Error> {
101        // Clause 12.33 holds the OUT_OF_SERVICE flag FALSE.
102        if let Some(result) =
103            read_common_properties!(self, property, array_index, no_out_of_service)
104        {
105            return result;
106        }
107        match property {
108            p if p == PropertyIdentifier::OBJECT_TYPE => {
109                Ok(PropertyValue::Enumerated(ObjectType::ACCESS_USER.to_raw()))
110            }
111            p if p == PropertyIdentifier::USER_TYPE => {
112                Ok(PropertyValue::Enumerated(self.user_type.to_raw()))
113            }
114            p if p == PropertyIdentifier::CREDENTIALS => {
115                Ok(crate::device_reference::reference_list(&self.credentials))
116            }
117            p if p == PropertyIdentifier::MEMBERS => {
118                Ok(crate::device_reference::reference_list(&self.members))
119            }
120            p if p == PropertyIdentifier::MEMBER_OF => {
121                Ok(crate::device_reference::reference_list(&self.member_of))
122            }
123            _ => Err(common::unknown_property_error()),
124        }
125    }
126
127    fn write_property(
128        &mut self,
129        property: PropertyIdentifier,
130        _array_index: Option<u32>,
131        value: PropertyValue,
132        _priority: Option<u8>,
133    ) -> Result<(), Error> {
134        if let Some(result) = common::write_description(&mut self.description, property, &value) {
135            return result;
136        }
137        match property {
138            p if p == PropertyIdentifier::USER_TYPE => {
139                if let PropertyValue::Enumerated(v) = value {
140                    self.user_type = AccessUserType::from_raw(v);
141                    Ok(())
142                } else {
143                    Err(common::invalid_data_type_error())
144                }
145            }
146            _ => Err(crate::common::unhandled_write_error(
147                self.property_metadata().as_ref(),
148                property,
149                _array_index,
150            )),
151        }
152    }
153
154    fn property_metadata(&self) -> Cow<'_, [crate::property_metadata::PropertyMetadata]> {
155        super::metadata_identity::for_access_user_object(self)
156    }
157
158    fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
159        crate::property_metadata::property_list_from_metadata(self.property_metadata().as_ref())
160    }
161}
162
163// ---------------------------------------------------------------------------