Skip to main content

bacnet_objects/event_log/
durable.rs

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