use super::staging::{operational_problem, StagedChange};
use super::*;
pub(super) type Timestamp = (
bacnet_types::primitives::Date,
bacnet_types::primitives::Time,
);
impl AuditLogObject {
pub fn purge(&mut self) -> Result<u64, Error> {
self.commit_change(StagedChange::Purge)?;
Ok(self.total_record_count)
}
pub(super) fn write_buffer_size(&mut self, value: &PropertyValue) -> Result<(), Error> {
let size = written_buffer_size(self.log_enable, value)?;
if size == self.buffer_size {
return Ok(());
}
self.commit_change(StagedChange::BufferSize(size))
}
}
pub(super) fn written_buffer_size(log_enable: bool, value: &PropertyValue) -> Result<u32, Error> {
if log_enable {
return Err(property_error(ErrorCode::WRITE_ACCESS_DENIED));
}
let PropertyValue::Unsigned(size) = value else {
return Err(property_error(ErrorCode::INVALID_DATA_TYPE));
};
u32::try_from(*size)
.ok()
.filter(|size| *size <= MAX_AUDIT_RECORDS)
.ok_or_else(|| property_error(ErrorCode::VALUE_OUT_OF_RANGE))
}
pub(super) fn apply_change(
snapshot: &mut AuditLogSnapshot,
change: StagedChange,
timestamp: Option<Timestamp>,
) -> Result<(), Error> {
match change {
StagedChange::LogEnable(log_enable) => {
let timestamp = timestamp.ok_or_else(operational_problem)?;
snapshot.log_enable = log_enable;
append_record(snapshot, log_enable_record(timestamp, log_enable));
}
StagedChange::BufferSize(size) => {
let dropped = snapshot.records.len().saturating_sub(size as usize);
snapshot.records.drain(..dropped);
snapshot.capacity = size;
}
StagedChange::Purge => {
let timestamp = timestamp.ok_or_else(operational_problem)?;
snapshot.records.clear();
let mut status = LogStatus::BUFFER_PURGED;
status.set(LogStatus::LOG_DISABLED, !snapshot.log_enable);
append_record(
snapshot,
BACnetAuditLogRecord {
timestamp,
datum: BACnetAuditLogDatum::LogStatus(status),
},
);
}
}
Ok(())
}
fn property_error(code: ErrorCode) -> Error {
Error::Protocol {
class: ErrorClass::PROPERTY.to_raw() as u32,
code: code.to_raw() as u32,
}
}