bacnet_encoding/constructed/
value_source.rs1use bacnet_types::constructed::{BACnetAddress, BACnetValueSource};
3use bacnet_types::error::Error;
4use bytes::BytesMut;
5
6use super::recipient::{check_encoded_mac_len, decode_app_mac_address};
7use super::tagged::{decode_app_unsigned, expect_closing};
8use super::{decode_device_object_reference, encode_device_object_reference};
9use crate::{primitives, tags};
10
11const WHAT: &str = "BACnetValueSource";
12
13pub fn encode_value_source(buf: &mut BytesMut, source: &BACnetValueSource) -> Result<(), Error> {
22 if let BACnetValueSource::Address(address) = source {
23 check_encoded_mac_len(&address.mac_address, WHAT)?;
24 }
25 match source {
26 BACnetValueSource::None => tags::encode_tag(buf, 0, tags::TagClass::Context, 0),
27 BACnetValueSource::Object(reference) => {
28 tags::encode_opening_tag(buf, 1);
29 encode_device_object_reference(buf, reference);
30 tags::encode_closing_tag(buf, 1);
31 }
32 BACnetValueSource::Address(address) => {
33 tags::encode_opening_tag(buf, 2);
34 primitives::encode_app_unsigned(buf, u64::from(address.network_number));
35 primitives::encode_app_octet_string(buf, &address.mac_address);
36 tags::encode_closing_tag(buf, 2);
37 }
38 }
39 Ok(())
40}
41
42pub fn decode_value_source(
50 data: &[u8],
51 offset: usize,
52) -> Result<(BACnetValueSource, usize), Error> {
53 let (tag, pos) = tags::decode_tag(data, offset)?;
54 if tag.is_context(0) && tag.length == 0 {
55 return Ok((BACnetValueSource::None, pos));
56 }
57 if tag.is_opening_tag(1) {
58 let (reference, end) = decode_device_object_reference(data, pos)?;
59 let end = expect_closing(data, end, 1, WHAT)?;
60 return Ok((BACnetValueSource::Object(reference), end));
61 }
62 if tag.is_opening_tag(2) {
63 let (network, pos) = decode_app_unsigned::<u64>(data, pos, WHAT)?;
64 let network_number = u16::try_from(network).map_err(|_| {
65 Error::out_of_range(pos, format!("{WHAT}: network number exceeds Unsigned16"))
66 })?;
67 let (mac_address, pos) = decode_app_mac_address(data, pos, WHAT)?;
68 let end = expect_closing(data, pos, 2, WHAT)?;
69 return Ok((
70 BACnetValueSource::Address(BACnetAddress {
71 network_number,
72 mac_address,
73 }),
74 end,
75 ));
76 }
77 Err(Error::decoding(
78 offset,
79 format!("{WHAT}: expected NULL [0], object [1], or address [2]"),
80 ))
81}