Skip to main content

bacnet_objects/event_log/
durable.rs

1//! An Event Log kept in storage (#1541); see [`crate::log_persistence`].
2
3use std::sync::Arc;
4
5use bacnet_types::constructed::BACnetEventLogRecord;
6use bacnet_types::error::Error;
7use bacnet_types::primitives::{Date, Time};
8
9use super::EventLogObject;
10use crate::log_buffer::LogRecordBuffer;
11use crate::log_persistence::store::{
12    fit_to_buffer_size, impl_durable_log, DurableLog, LogState, LogStore,
13};
14use crate::log_persistence::{LogCommitCadence, LogPersistence};
15
16impl EventLogObject {
17    /// Open an Event Log kept in `persistence`, or start one there when it
18    /// holds none yet, as
19    /// [`TrendLogObject::with_persistence`](crate::trend::TrendLogObject::with_persistence)
20    /// does. An Event Log's snapshot has no acquisition settings or
21    /// references, and whether it logs received notifications is the
22    /// application's to set on each start.
23    pub fn with_persistence(
24        instance: u32,
25        name: impl Into<String>,
26        buffer_size: u32,
27        persistence: Arc<dyn LogPersistence<BACnetEventLogRecord>>,
28    ) -> Result<Self, Error> {
29        let mut log = Self::new(instance, name, buffer_size)?;
30        let (mut store, loaded) = LogStore::open(log.oid, buffer_size, persistence)?;
31        if let Some(mut snapshot) = loaded {
32            let resized = fit_to_buffer_size(&mut snapshot, buffer_size);
33            log.lifecycle().reopen(&mut snapshot)?;
34            store.reopened(log.log_state(), resized);
35        }
36        log.store = Some(store);
37        Ok(log)
38    }
39
40    /// Whether the log came back from a snapshot its storage held, rather
41    /// than starting empty. Always false without storage.
42    pub fn reopened(&self) -> bool {
43        self.store.as_ref().is_some_and(LogStore::is_reopened)
44    }
45
46    /// When the log commits to its storage; `None` without storage.
47    pub fn commit_cadence(&self) -> Option<LogCommitCadence> {
48        self.store.as_ref().map(LogStore::cadence)
49    }
50
51    /// Set when the log commits to its storage. Does nothing without
52    /// storage.
53    pub fn set_commit_cadence(&mut self, cadence: LogCommitCadence) {
54        if let Some(store) = &mut self.store {
55            store.set_cadence(cadence);
56        }
57    }
58
59    /// The generation of the last snapshot storage took, as
60    /// [`TrendLogObject::storage_generation`](crate::trend::TrendLogObject::storage_generation)
61    /// gives it.
62    pub fn storage_generation(&self) -> Option<u64> {
63        self.store.as_ref().map(LogStore::generation)
64    }
65}
66
67impl DurableLog for EventLogObject {
68    type Record = BACnetEventLogRecord;
69
70    fn log_state(&self) -> LogState {
71        LogState::of(
72            &self.log_buffer,
73            self.log_enable,
74            self.stop_when_full,
75            &self.window,
76            &self.reporting,
77        )
78    }
79
80    fn durable_parts(
81        &mut self,
82    ) -> (
83        Option<&mut LogStore<BACnetEventLogRecord>>,
84        &LogRecordBuffer<BACnetEventLogRecord>,
85    ) {
86        (self.store.as_mut(), &self.log_buffer)
87    }
88
89    fn record_owed_interruption(&mut self, fallback: Option<(Date, Time)>) -> bool {
90        self.lifecycle().record_interruption_now(fallback)
91    }
92}
93
94impl_durable_log!(EventLogObject);