#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use bacnet_types::constructed::{PropertyReference, ReadAccessSpecification};
use bacnet_types::enums::PropertyIdentifier;
use bacnet_types::error::Error;
use bytes::BytesMut;
use super::tagged::{
decode_ctx_object_id, decode_ctx_unsigned, decode_optional_ctx, expect_opening,
};
use super::MAX_FRAMED_ITEMS;
use crate::{primitives, tags};
pub fn encode_property_reference(buf: &mut BytesMut, reference: &PropertyReference) {
primitives::encode_ctx_unsigned(buf, 0, u64::from(reference.property_identifier.to_raw()));
if let Some(index) = reference.property_array_index {
primitives::encode_ctx_unsigned(buf, 1, u64::from(index));
}
}
pub fn decode_property_reference(
data: &[u8],
offset: usize,
) -> Result<(PropertyReference, usize), Error> {
const PROPERTY: &str = "PropertyReference property-id";
const INDEX: &str = "PropertyReference array-index";
let (property, next) = decode_ctx_unsigned::<u32>(data, offset, 0, PROPERTY)?;
let (property_array_index, offset) =
decode_optional_ctx(data, next, 1, INDEX, decode_ctx_unsigned::<u32>)?;
Ok((
PropertyReference {
property_identifier: PropertyIdentifier::from_raw(property),
property_array_index,
},
offset,
))
}
pub fn encode_read_access_specification(buf: &mut BytesMut, spec: &ReadAccessSpecification) {
primitives::encode_ctx_object_id(buf, 0, &spec.object_identifier);
tags::encode_opening_tag(buf, 1);
for reference in &spec.list_of_property_references {
encode_property_reference(buf, reference);
}
tags::encode_closing_tag(buf, 1);
}
pub fn decode_read_access_specification(
data: &[u8],
offset: usize,
) -> Result<(ReadAccessSpecification, usize), Error> {
const WHAT: &str = "ReadAccessSpecification";
let (object_identifier, end) = decode_ctx_object_id(data, offset, 0, WHAT)?;
let mut offset = expect_opening(data, end, 1, WHAT)?;
let mut list_of_property_references = Vec::new();
loop {
if offset >= data.len() {
return Err(Error::missing(
offset,
format!("{WHAT} missing closing tag 1"),
));
}
if list_of_property_references.len() >= MAX_FRAMED_ITEMS {
return Err(Error::overflow(
offset,
format!("{WHAT} property references exceed the item limit"),
));
}
let (tag, tag_end) = tags::decode_tag(data, offset)?;
if tag.is_closing_tag(1) {
offset = tag_end;
break;
}
let (reference, next) = decode_property_reference(data, offset)?;
list_of_property_references.push(reference);
offset = next;
}
Ok((
ReadAccessSpecification {
object_identifier,
list_of_property_references,
},
offset,
))
}