use super::MessageError;
use crate::conn::{frame::Frame, MessageKind};
pub(super) type ControlStatusMessageSubtype = u8;
const MSG_SUBTYPE_SIZE: usize = std::mem::size_of::<ControlStatusMessageSubtype>();
macro_rules! control_status_message {
( $subtype:expr,
$vis:vis struct $name:ident { $($fields:tt)* }
$(,)?
{ $($impl:tt)* } ) => {
use crate::conn::frame::Frame;
use super::MessageError;
#[derive(Clone, Debug, PartialEq)]
$vis struct $name {
message_id: u8,
is_request: bool,
$($fields)*
}
impl ControlStatusMessage for $name {
const MSG_SUBTYPE: ControlStatusMessageSubtype = ($subtype);
fn message_id(&self) -> u8 { self.message_id }
fn is_request(&self) -> bool { self.is_request }
$($impl)*
}
impl TryFrom<Frame> for $name {
type Error = MessageError;
fn try_from(value: Frame) -> Result<Self, Self::Error> { Self::from_frame(value) }
}
impl TryFrom<$name> for Frame {
type Error = MessageError;
fn try_from(value: $name) -> Result<Self, Self::Error> { value.into_frame() }
}
};
}
pub(super) use control_status_message;
const MSG_TYPE_CONTOL_STATUS: u8 = 0xc0;
pub(super) const MSG_HEADER_SIZE: usize = 8;
pub(super) trait ControlStatusMessage: Sized {
const MSG_SUBTYPE: ControlStatusMessageSubtype;
fn impl_frame_normal_len(&self) -> usize;
fn impl_frame_repeat_len(&self) -> usize;
fn impl_frame_repeat_count(&self) -> u16;
fn impl_frame_normal_data<W: std::io::Write>(&self, dst: &mut W) -> Result<(), MessageError>;
fn impl_frame_repeat_data<W: std::io::Write>(
&self,
index: u16,
dst: &mut W,
) -> Result<(), MessageError>;
fn from_frame_data(
message_id: u8,
is_request: bool,
normal_data: Vec<u8>,
repeat_data: Vec<Vec<u8>>,
) -> Result<Self, MessageError>;
fn message_id(&self) -> u8;
fn is_request(&self) -> bool;
fn from_frame(mut frame: Frame) -> Result<Self, MessageError> {
if peek_subtype(&frame)? != Self::MSG_SUBTYPE {
return Err(MessageError::IncorrectSubtype(super::Frame {
inner: frame,
}));
}
if frame.data.len() < MSG_HEADER_SIZE {
return Err(MessageError::InvalidData);
}
let head: Vec<u8> = frame.data.drain(..MSG_HEADER_SIZE).collect();
let mut i = head
.chunks_exact(2)
.map(|x| u16::from_be_bytes(x.try_into().unwrap()) as usize);
let _ = i.next();
let normal_len = i.next().unwrap();
let repeat_len = i.next().unwrap();
let repeat_count = i.next().unwrap();
if frame.data.len() != normal_len + repeat_count * repeat_len {
return Err(MessageError::InvalidData);
}
let normal_data = frame.data.drain(..normal_len).collect();
let mut repeat_data = Vec::new();
for _ in 0..repeat_count {
repeat_data.push(frame.data.drain(..repeat_len).collect());
}
Self::from_frame_data(
frame.msg_id,
frame.kind == MessageKind::ControlRequest,
normal_data,
repeat_data,
)
}
fn into_frame(self) -> Result<Frame, MessageError> {
use std::io::Write;
let kind = if self.is_request() {
MessageKind::ControlRequest
} else {
MessageKind::StatusResponse
};
let (msg_type, address) = kind.into();
let normal_len = self.impl_frame_normal_len();
let repeat_len = self.impl_frame_repeat_len();
let repeat_count = self.impl_frame_repeat_count();
let mut data = std::io::Cursor::new(Vec::with_capacity(
MSG_HEADER_SIZE + normal_len + repeat_len * repeat_count as usize,
));
data.write_all(&Self::MSG_SUBTYPE.to_be_bytes())?;
data.write_all(&0u8.to_be_bytes())?;
data.write_all(&(normal_len as u16).to_be_bytes())?;
data.write_all(&(repeat_len as u16).to_be_bytes())?;
data.write_all(&repeat_count.to_be_bytes())?;
self.impl_frame_normal_data(&mut data)?;
for i in 0..repeat_count {
self.impl_frame_repeat_data(i, &mut data)?
}
Ok(Frame {
address,
msg_id: self.message_id(),
msg_type,
kind,
data: data.into_inner(),
})
}
}
pub(super) fn peek_subtype(frame: &Frame) -> Result<ControlStatusMessageSubtype, MessageError> {
if frame.msg_type != MSG_TYPE_CONTOL_STATUS || frame.data.len() < MSG_SUBTYPE_SIZE {
return Err(MessageError::InvalidData);
}
Ok(ControlStatusMessageSubtype::from_be_bytes(
frame.data[..MSG_SUBTYPE_SIZE].try_into().unwrap(),
))
}