use bacnet_types::constructed::BACnetObjectPropertyReference;
use bacnet_types::error::Error;
use bytes::BytesMut;
use crate::primitives;
use crate::tags;
use super::tagged::{
decode_ctx_constructed, decode_ctx_object_id, decode_ctx_unsigned, decode_optional_ctx,
expect_end, next_is_context,
};
const WHAT: &str = "BACnetObjectPropertyReference";
const SETPOINT: &str = "BACnetSetpointReference";
pub fn encode_object_property_reference(buf: &mut BytesMut, r: &BACnetObjectPropertyReference) {
primitives::encode_ctx_object_id(buf, 0, &r.object_identifier);
primitives::encode_ctx_unsigned(buf, 1, r.property_identifier as u64);
if let Some(index) = r.property_array_index {
primitives::encode_ctx_unsigned(buf, 2, index as u64);
}
}
pub fn encode_setpoint_reference(buf: &mut BytesMut, r: &BACnetObjectPropertyReference) {
tags::encode_opening_tag(buf, 0);
encode_object_property_reference(buf, r);
tags::encode_closing_tag(buf, 0);
}
pub fn decode_object_property_reference_at(
data: &[u8],
offset: usize,
) -> Result<(BACnetObjectPropertyReference, usize), Error> {
let (object_identifier, offset) = decode_ctx_object_id(data, offset, 0, WHAT)?;
let (property_identifier, offset) = decode_ctx_unsigned::<u32>(data, offset, 1, WHAT)?;
let (property_array_index, offset) =
decode_optional_ctx(data, offset, 2, WHAT, decode_ctx_unsigned::<u32>)?;
if next_is_context(data, offset, 3)? {
return Err(Error::decoding(
offset,
format!("{WHAT}: [3] device-identifier is not part of this production"),
));
}
Ok((
BACnetObjectPropertyReference {
object_identifier,
property_identifier,
property_array_index,
},
offset,
))
}
pub fn decode_object_property_reference(
data: &[u8],
) -> Result<BACnetObjectPropertyReference, Error> {
let (reference, end) = decode_object_property_reference_at(data, 0)?;
expect_end(data, end, end, WHAT)?;
Ok(reference)
}
pub fn decode_setpoint_reference_at(
data: &[u8],
offset: usize,
) -> Result<(BACnetObjectPropertyReference, usize), Error> {
let (inner, after) = decode_ctx_constructed(data, offset, 0, SETPOINT)?;
let (reference, end) = decode_object_property_reference_at(inner, 0)?;
expect_end(inner, end, offset, SETPOINT)?;
Ok((reference, after))
}
pub fn decode_setpoint_reference(
data: &[u8],
) -> Result<Option<BACnetObjectPropertyReference>, Error> {
if data.is_empty() {
return Ok(None);
}
let (reference, after) = decode_setpoint_reference_at(data, 0)?;
expect_end(data, after, after, SETPOINT)?;
Ok(Some(reference))
}
#[cfg(test)]
mod tests;