use bacnet_types::constructed::{BACnetPrescale, BACnetScale};
use bacnet_types::error::Error;
use bytes::BytesMut;
use super::tagged::{decode_ctx_primitive, decode_ctx_real, decode_ctx_unsigned, misplaced_tag};
use crate::{primitives, tags};
const SCALE: &str = "BACnetScale";
const PRESCALE: &str = "BACnetPrescale";
pub fn encode_scale(buf: &mut BytesMut, scale: &BACnetScale) {
match *scale {
BACnetScale::FloatScale(factor) => primitives::encode_ctx_real(buf, 0, factor),
BACnetScale::IntegerScale(power) => primitives::encode_ctx_signed(buf, 1, power),
}
}
pub fn decode_scale(data: &[u8], offset: usize) -> Result<(BACnetScale, usize), Error> {
let (tag, _) = tags::decode_tag(data, offset)?;
if tag.is_context(0) {
let (factor, end) = decode_ctx_real(data, offset, 0, SCALE)?;
return Ok((BACnetScale::FloatScale(factor), end));
}
if tag.is_context(1) {
let (octets, end) = decode_ctx_primitive(data, offset, 1, SCALE)?;
let power = primitives::decode_signed(octets).map_err(|_| {
Error::decoding(
offset,
format!("{SCALE}: integer-scale [1] needs 1 to 4 octets"),
)
})?;
return Ok((BACnetScale::IntegerScale(power), end));
}
Err(misplaced_tag(
data,
&tag,
None,
offset,
format!("{SCALE}: expected float-scale [0] or integer-scale [1]"),
))
}
pub fn encode_prescale(buf: &mut BytesMut, prescale: &BACnetPrescale) {
primitives::encode_ctx_unsigned(buf, 0, u64::from(prescale.multiplier));
primitives::encode_ctx_unsigned(buf, 1, u64::from(prescale.modulo_divide));
}
pub fn decode_prescale(data: &[u8], offset: usize) -> Result<(BACnetPrescale, usize), Error> {
let (multiplier, pos) = decode_ctx_unsigned::<u32>(data, offset, 0, PRESCALE)?;
let (modulo_divide, end) = decode_ctx_unsigned::<u32>(data, pos, 1, PRESCALE)?;
Ok((
BACnetPrescale {
multiplier,
modulo_divide,
},
end,
))
}