1use std::collections::{HashMap, HashSet};
4use std::sync::Arc;
5
6use bacnet_types::enums::{ErrorClass, ErrorCode, ObjectType};
7use bacnet_types::error::Error;
8use bacnet_types::primitives::ObjectIdentifier;
9
10use crate::clock::{ClockFrame, ClockReader};
11use crate::event_enrollment::EventEnrollmentMonitoredSource;
12use crate::traits::{BACnetObject, DeadlineWaker, MonotonicClock};
13
14mod averaging_sampling;
15mod event_algorithm_inhibit;
16mod event_log;
17mod input_references;
18mod local_device;
19mod membership;
20mod network_port;
21mod trend_poll;
22pub use local_device::LocalDevice;
23#[doc(hidden)]
24pub use membership::{MembershipWaker, MembershipWork};
25use trend_poll::TrendPollSchedule;
26
27pub struct ObjectDatabase {
32 audit_owner: Option<std::sync::Weak<AuditOwnership>>,
33 network_port: Option<network_port::NetworkPortRegistration>,
34 objects: HashMap<ObjectIdentifier, Box<dyn BACnetObject>>,
35 trend_poll: TrendPollSchedule,
36 clock: Option<Arc<dyn ClockReader>>,
38 monotonic_clock: Option<Arc<MonotonicClock>>,
39 deadline_waker: Option<Arc<DeadlineWaker>>,
41 event_sequence: Arc<EventSequence>,
43 name_index: HashMap<String, ObjectIdentifier>,
45 type_index: HashMap<ObjectType, Vec<ObjectIdentifier>>,
47 invalid_enrollment_eval_state: HashSet<ObjectIdentifier>,
50 enrollment_eval_sources: HashMap<ObjectIdentifier, EventEnrollmentMonitoredSource>,
53 membership: membership::MembershipQueue,
55}
56
57#[doc(hidden)]
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub struct EventSequenceReservation {
61 number: u16,
62}
63
64impl EventSequenceReservation {
65 #[doc(hidden)]
67 pub fn number(self) -> u16 {
68 self.number
69 }
70}
71
72mod audit_ownership;
73mod event_sequence;
74pub use audit_ownership::AuditOwnership;
75pub use event_sequence::EventSequence;
76
77impl Default for ObjectDatabase {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83impl ObjectDatabase {
84 pub fn new() -> Self {
86 Self {
87 objects: HashMap::new(),
88 trend_poll: TrendPollSchedule::default(),
89 clock: None,
90 monotonic_clock: None,
91 deadline_waker: None,
92 event_sequence: Arc::default(),
93 audit_owner: None,
94 network_port: None,
95 name_index: HashMap::new(),
96 type_index: HashMap::new(),
97 invalid_enrollment_eval_state: HashSet::new(),
98 enrollment_eval_sources: HashMap::new(),
99 membership: membership::MembershipQueue::default(),
100 }
101 }
102
103 pub fn add(&mut self, mut object: Box<dyn BACnetObject>) -> Result<(), Error> {
118 self.check_network_port_membership(&object.object_identifier())?;
119 self.check_audit_membership(&object.object_identifier(), true)?;
120 object.bind_clock_internal(self.clock.clone());
121 object.bind_monotonic_clock_internal(self.monotonic_clock.clone());
122 object.bind_deadline_waker_internal(self.deadline_waker.clone());
123 let oid = object.object_identifier();
124 let name = object.object_name().to_string();
125
126 self.check_name_available(&oid, &name)?;
128
129 if let Some(old) = self.objects.get(&oid) {
132 if let Some(reporter) = old.audit_reporter_internal() {
133 reporter.status_internal().configuration_changed();
134 }
135 let old_name = old.object_name().to_string();
136 self.name_index.remove(&old_name);
137 self.invalidate_enrollments_monitoring(&oid);
138 }
139
140 self.name_index.insert(name, oid);
141 let is_new = !self.objects.contains_key(&oid);
142 self.enrollment_eval_sources.remove(&oid);
143 self.trend_poll.retire(&oid);
144 self.objects.insert(oid, object);
145 self.audit_membership_changed(oid, true);
146 if is_new {
147 self.type_index
148 .entry(oid.object_type())
149 .or_default()
150 .push(oid);
151 }
152 self.membership_changed(oid, true);
153 Ok(())
154 }
155
156 pub fn find_by_name(&self, name: &str) -> Option<&dyn BACnetObject> {
158 let oid = self.name_index.get(name)?;
159 self.objects.get(oid).map(|o| o.as_ref())
160 }
161
162 pub fn check_name_available(
171 &self,
172 oid: &ObjectIdentifier,
173 new_name: &str,
174 ) -> Result<(), Error> {
175 if let Some(&owner) = self.name_index.get(new_name) {
176 if owner != *oid {
177 return Err(Error::Protocol {
178 class: ErrorClass::PROPERTY.to_raw() as u32,
179 code: ErrorCode::DUPLICATE_NAME.to_raw() as u32,
180 });
181 }
182 }
183 Ok(())
184 }
185
186 pub fn update_name_index(&mut self, oid: &ObjectIdentifier) {
190 if let Some(obj) = self.objects.get(oid) {
191 self.name_index.retain(|_, v| v != oid);
193 self.name_index.insert(obj.object_name().to_string(), *oid);
195 }
196 }
197
198 pub fn get(&self, oid: &ObjectIdentifier) -> Option<&dyn BACnetObject> {
200 self.objects.get(oid).map(|o| o.as_ref())
201 }
202
203 pub fn get_mut(&mut self, oid: &ObjectIdentifier) -> Option<&mut (dyn BACnetObject + '_)> {
205 if let Some(object) = self.objects.get_mut(oid) {
206 Some(object.as_mut())
207 } else {
208 None
209 }
210 }
211
212 pub fn with_object_adapter<R, F>(
230 &mut self,
231 oid: &ObjectIdentifier,
232 adapt: F,
233 ) -> Result<Option<R>, Error>
234 where
235 F: for<'slot> FnOnce(&'slot mut Box<dyn BACnetObject>) -> R,
236 {
237 self.check_network_port_membership(oid)?;
238 self.check_audit_membership(oid, false)?;
239 self.trend_poll.retire(oid);
240 Ok(self.objects.get_mut(oid).map(adapt))
241 }
242
243 pub fn enrollment_eval_state_invalidated(&self, oid: &ObjectIdentifier) -> bool {
246 self.invalid_enrollment_eval_state.contains(oid)
247 }
248
249 pub fn set_enrollment_eval_state_invalidated(
251 &mut self,
252 oid: ObjectIdentifier,
253 invalidated: bool,
254 ) {
255 if invalidated {
256 self.invalid_enrollment_eval_state.insert(oid);
257 } else {
258 self.invalid_enrollment_eval_state.remove(&oid);
259 }
260 }
261
262 pub fn enrollment_eval_source(
265 &self,
266 oid: &ObjectIdentifier,
267 ) -> Option<EventEnrollmentMonitoredSource> {
268 self.enrollment_eval_sources.get(oid).copied()
269 }
270
271 pub fn set_enrollment_eval_source(
274 &mut self,
275 oid: ObjectIdentifier,
276 source: Option<EventEnrollmentMonitoredSource>,
277 ) {
278 if let Some(source) = source {
279 self.enrollment_eval_sources.insert(oid, source);
280 } else {
281 self.enrollment_eval_sources.remove(&oid);
282 }
283 }
284
285 fn invalidate_enrollments_monitoring(&mut self, monitored_oid: &ObjectIdentifier) {
286 let affected = self
287 .objects
288 .iter()
289 .filter_map(|(oid, object)| {
290 let source = object
291 .enrollment_eval_source_internal()
292 .flatten()
293 .or_else(|| self.enrollment_eval_sources.get(oid).copied());
294 source
295 .is_some_and(|source| source.0 == *monitored_oid)
296 .then_some(*oid)
297 })
298 .collect::<Vec<_>>();
299 self.invalid_enrollment_eval_state.extend(affected);
300 }
301
302 pub fn remove(
307 &mut self,
308 oid: &ObjectIdentifier,
309 ) -> Result<Option<Box<dyn BACnetObject>>, Error> {
310 self.check_network_port_membership(oid)?;
311 self.check_audit_membership(oid, false)?;
312 self.trend_poll.retire(oid);
313 if self.objects.contains_key(oid) {
314 self.invalidate_enrollments_monitoring(oid);
315 }
316 if let Some(mut obj) = self.objects.remove(oid) {
317 if let Some(reporter) = obj.audit_reporter_internal() {
318 reporter.status_internal().configuration_changed();
319 }
320 self.enrollment_eval_sources.remove(oid);
321 if obj.enrollment_eval_state_internal().is_some() {
322 if obj
323 .set_enrollment_eval_state_internal(Default::default())
324 .is_err()
325 {
326 self.invalid_enrollment_eval_state.insert(*oid);
327 } else {
328 self.invalid_enrollment_eval_state.remove(oid);
329 }
330 let _ = obj.set_enrollment_eval_source_internal(None);
331 } else {
332 self.invalid_enrollment_eval_state.remove(oid);
333 }
334 self.name_index.remove(obj.object_name());
335 if let Some(type_set) = self.type_index.get_mut(&oid.object_type()) {
336 type_set.retain(|o| o != oid);
337 }
338 self.audit_membership_changed(*oid, false);
339 self.membership_changed(*oid, false);
340 Ok(Some(obj))
341 } else {
342 Ok(None)
343 }
344 }
345
346 pub fn list_objects(&self) -> Vec<ObjectIdentifier> {
348 self.objects.keys().copied().collect()
349 }
350
351 pub fn find_by_type(&self, object_type: ObjectType) -> Vec<ObjectIdentifier> {
356 self.type_index
357 .get(&object_type)
358 .cloned()
359 .unwrap_or_default()
360 }
361
362 pub fn iter_objects(&self) -> impl Iterator<Item = (ObjectIdentifier, &dyn BACnetObject)> {
366 self.objects.iter().map(|(&oid, obj)| (oid, obj.as_ref()))
367 }
368
369 pub fn set_clock_reader(&mut self, clock: Option<Arc<dyn ClockReader>>) {
373 self.clock = clock;
374 for object in self.objects.values_mut() {
375 object.bind_clock_internal(self.clock.clone());
376 }
377 }
378
379 #[doc(hidden)]
381 pub fn set_monotonic_clock_internal(&mut self, clock: Option<Arc<MonotonicClock>>) {
382 self.trend_poll.clear();
383 self.monotonic_clock = clock;
384 for object in self.objects.values_mut() {
385 object.bind_monotonic_clock_internal(self.monotonic_clock.clone());
386 }
387 }
388
389 #[doc(hidden)]
392 pub fn set_deadline_waker_internal(&mut self, waker: Option<Arc<DeadlineWaker>>) {
393 self.deadline_waker = waker;
394 for object in self.objects.values_mut() {
395 object.bind_deadline_waker_internal(self.deadline_waker.clone());
396 }
397 }
398
399 pub fn clock_frame(&self) -> Option<ClockFrame> {
401 self.clock.as_ref()?.read_clock()
402 }
403
404 #[doc(hidden)]
405 pub fn event_sequence_internal(&self) -> Arc<EventSequence> {
406 Arc::clone(&self.event_sequence)
407 }
408
409 #[doc(hidden)]
413 pub fn next_event_sequence_number(&mut self) -> u16 {
414 let reservation = self.reserve_event_sequence_number();
415 let number = reservation.number();
416 let confirmed = self.confirm_event_sequence_number(reservation);
417 debug_assert!(
418 confirmed,
419 "a reservation cannot become stale without mutation"
420 );
421 number
422 }
423
424 #[doc(hidden)]
426 pub fn reserve_event_sequence_number(&self) -> EventSequenceReservation {
427 EventSequenceReservation {
428 number: self.event_sequence.current(),
429 }
430 }
431
432 #[doc(hidden)]
434 pub fn confirm_event_sequence_number(&mut self, reservation: EventSequenceReservation) -> bool {
435 self.event_sequence.confirm(reservation.number)
436 }
437
438 pub fn for_each_object_mut<F>(&mut self, mut f: F)
445 where
446 F: FnMut(ObjectIdentifier, &mut dyn BACnetObject),
447 {
448 for (&oid, obj) in self.objects.iter_mut() {
449 f(oid, obj.as_mut());
450 }
451 }
452
453 pub fn len(&self) -> usize {
455 self.objects.len()
456 }
457
458 pub fn is_empty(&self) -> bool {
460 self.objects.is_empty()
461 }
462}
463
464#[cfg(test)]
465mod tests;
466
467#[cfg(test)]
468mod network_port_tests;