use std::collections::VecDeque;
use super::*;
use bacnet_encoding::constructed::encode_audit_log_record;
use bacnet_objects::log_buffer::LogBufferRecords;
use bacnet_types::constructed::BACnetAuditLogRecordResult;
pub(crate) enum RangeItems<'a> {
Values(Vec<PropertyValue>),
AuditRecords(&'a VecDeque<BACnetAuditLogRecordResult>),
LogRecords(&'a dyn LogBufferRecords),
}
impl RangeItems<'_> {
pub(super) fn len(&self) -> usize {
match self {
Self::Values(items) => items.len(),
Self::AuditRecords(records) => records.len(),
Self::LogRecords(records) => records.record_count(),
}
}
pub(super) fn encode_with<F>(
&self,
index: usize,
buf: &mut BytesMut,
encode_value: &mut F,
) -> Result<(), Error>
where
F: FnMut(&mut BytesMut, &PropertyValue) -> Result<(), Error>,
{
match self {
Self::Values(items) => encode_value(buf, &items[index]),
Self::AuditRecords(records) => encode_audit_log_record(&records[index].record, buf),
Self::LogRecords(records) => {
records.encode_record(index, buf);
Ok(())
}
}
}
}
pub(super) type LogBuffer<'a> = (RangeItems<'a>, Option<Vec<LogRecordIdentity>>);
pub(super) fn log_buffer<'a>(
object: &'a dyn BACnetObject,
request: &ReadRangeRequest,
) -> Result<Option<LogBuffer<'a>>, Error> {
if request.property_identifier != PropertyIdentifier::LOG_BUFFER {
return Ok(None);
}
let resolved = if let Some(storage) = object.audit_log_storage_internal() {
let records = storage.retained_records();
let identities = records
.iter()
.map(|result| {
let (date, time) = result.record.timestamp;
LogRecordIdentity::new(result.sequence_number, date, time)
})
.collect();
(RangeItems::AuditRecords(records), identities)
} else if let Some(records) = object.log_buffer_internal() {
(
RangeItems::LogRecords(records),
object.log_record_identities_internal(),
)
} else {
return Ok(None);
};
if request.property_array_index.is_some() {
return Err(Error::Protocol {
class: ErrorClass::PROPERTY.to_raw() as u32,
code: ErrorCode::PROPERTY_IS_NOT_AN_ARRAY.to_raw() as u32,
});
}
Ok(Some(resolved))
}