use bacnet_types::primitives::BACnetTimeStamp;
use crate::sink::{EncodeSink, SinkFull};
use crate::tags::{self, TagClass};
use super::{encode_app_date_to_sink, encode_app_time_to_sink, encode_ctx_unsigned_to_sink};
pub fn encode_timestamp_choice_to_sink<S: EncodeSink + ?Sized>(
sink: &mut S,
timestamp: &BACnetTimeStamp,
) -> Result<usize, SinkFull> {
let mut encoded = [0; 12];
let used = stage_choice(&mut &mut encoded[..], timestamp)
.expect("each timestamp choice fits twelve bytes");
write_timestamp(sink, &encoded[..used])
}
pub fn encode_timestamp_to_sink<S: EncodeSink + ?Sized>(
sink: &mut S,
tag_number: u8,
timestamp: &BACnetTimeStamp,
) -> Result<usize, SinkFull> {
let mut encoded = [0; 16];
let mut tail = &mut encoded[..];
let opening = tags::encode_opening_tag_to_sink(&mut tail, tag_number)
.expect("an opening marker fits the timestamp staging buffer");
let inner = stage_choice(&mut tail, timestamp)
.expect("the timestamp choice fits after its opening marker");
let closing = tags::encode_closing_tag_to_sink(&mut tail, tag_number)
.expect("the closing marker fits after the timestamp choice");
let used = opening + inner + closing;
write_timestamp(sink, &encoded[..used])
}
fn stage_choice(tail: &mut &mut [u8], timestamp: &BACnetTimeStamp) -> Result<usize, SinkFull> {
let before = tail.len();
match timestamp {
BACnetTimeStamp::Time(time) => {
tags::encode_tag_to_sink(tail, 0, TagClass::Context, 4)?;
tail.write(&time.encode())?;
}
BACnetTimeStamp::SequenceNumber(number) => {
encode_ctx_unsigned_to_sink(tail, 1, u64::from(*number))?;
}
BACnetTimeStamp::DateTime { date, time } => {
tags::encode_opening_tag_to_sink(tail, 2)?;
encode_app_date_to_sink(tail, date)?;
encode_app_time_to_sink(tail, time)?;
tags::encode_closing_tag_to_sink(tail, 2)?;
}
}
Ok(before - tail.len())
}
fn write_timestamp<S: EncodeSink + ?Sized>(
sink: &mut S,
encoded: &[u8],
) -> Result<usize, SinkFull> {
if let Some(available) = sink.remaining_capacity()
&& available < encoded.len()
{
return Err(SinkFull {
needed: encoded.len(),
available,
});
}
sink.write(encoded)?;
Ok(encoded.len())
}