1pub use bacnet_types::constructed::{
10 AuditPropertyReference, BACnetAuditLogDatum, BACnetAuditLogQueryParameters,
11 BACnetAuditLogRecord, BACnetAuditLogRecordResult, BACnetAuditNotification,
12};
13use bacnet_types::error::Error;
14use bacnet_types::primitives::ObjectIdentifier;
15use bytes::BytesMut;
16
17use crate::common::PropertyReference;
18
19#[path = "audit/notification_codec.rs"]
20mod notification_codec;
21#[path = "audit/query_ack_codec.rs"]
22mod query_ack_codec;
23#[path = "audit/query_codec.rs"]
24mod query_codec;
25
26#[derive(Debug, Clone, PartialEq)]
28pub struct AuditNotificationRequest {
29 pub notifications: Vec<BACnetAuditNotification>,
31}
32
33#[derive(Debug, Clone, PartialEq)]
38pub struct AuditLogQueryAck {
39 pub audit_log: ObjectIdentifier,
40 pub records: Vec<BACnetAuditLogRecordResult>,
42 pub no_more_items: bool,
43}
44
45impl From<PropertyReference> for AuditPropertyReference {
51 fn from(value: PropertyReference) -> Self {
52 Self {
53 property_identifier: value.property_identifier,
54 property_array_index: value.property_array_index.map(u64::from),
55 }
56 }
57}
58
59impl TryFrom<AuditPropertyReference> for PropertyReference {
60 type Error = Error;
61
62 fn try_from(value: AuditPropertyReference) -> Result<Self, Self::Error> {
63 Ok(Self {
64 property_identifier: value.property_identifier,
65 property_array_index: value
66 .property_array_index
67 .map(u32::try_from)
68 .transpose()
69 .map_err(|_| {
70 Error::OutOfRange(
71 "Audit property-array-index exceeds shared PropertyReference u32 limit"
72 .into(),
73 )
74 })?,
75 })
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
81pub struct AuditLogQueryRequest {
82 pub audit_log: ObjectIdentifier,
83 pub query_parameters: BACnetAuditLogQueryParameters,
84 pub start_at_sequence_number: Option<u32>,
86 pub requested_count: u16,
87}
88
89fn decode_canonical_unsigned(data: &[u8], offset: usize, field: &str) -> Result<u64, Error> {
90 if data.len() > 1 && data.first() == Some(&0) {
91 return Err(Error::decoding(
92 offset,
93 format!("{field} must use the shortest Unsigned/Enumerated encoding"),
94 ));
95 }
96 bacnet_encoding::primitives::decode_unsigned(data)
97}
98
99impl AuditNotificationRequest {
100 pub fn try_encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
102 notification_codec::encode(self, buf)
103 }
104
105 pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
106 self.try_encode(buf)
107 }
108
109 pub fn decode(data: &[u8]) -> Result<Self, Error> {
111 notification_codec::decode(data)
112 }
113}
114
115impl AuditLogQueryRequest {
116 pub fn try_encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
118 query_codec::encode(self, buf)
119 }
120
121 pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
122 self.try_encode(buf)
123 }
124
125 pub fn decode(data: &[u8]) -> Result<Self, Error> {
127 query_codec::decode(data)
128 }
129}
130
131impl AuditLogQueryAck {
132 pub fn try_encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
134 query_ack_codec::encode(self, buf)
135 }
136
137 pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
138 self.try_encode(buf)
139 }
140
141 pub fn decode(data: &[u8]) -> Result<Self, Error> {
143 query_ack_codec::decode(data)
144 }
145}
146
147#[cfg(test)]
148#[path = "audit/tests.rs"]
149mod tests;
150
151#[cfg(test)]
152#[path = "audit/malformed_tests.rs"]
153mod malformed_tests;