use crate::framing::{self, FrameError};
use ptrs::trace;
use tokio_util::bytes::{Buf, BufMut};
pub(crate) const MESSAGE_OVERHEAD: usize = 2 + 1;
pub(crate) const MAX_MESSAGE_PAYLOAD_LENGTH: usize =
framing::MAX_FRAME_PAYLOAD_LENGTH - MESSAGE_OVERHEAD;
pub type MessageType = u8;
pub trait Message {
type Output;
fn as_pt(&self) -> MessageType;
fn marshall<T: BufMut>(&self, dst: &mut T) -> Result<(), FrameError>;
fn try_parse<T: BufMut + Buf>(buf: &mut T) -> Result<Self::Output, FrameError>;
}
pub fn build_and_marshall<T: BufMut>(
dst: &mut T,
pt: MessageType,
data: impl AsRef<[u8]>,
pad_len: usize,
) -> Result<(), FrameError> {
if pad_len > u16::MAX as usize {
Err(FrameError::InvalidPayloadLength(pad_len))?
}
let buf = data.as_ref();
let total_size = buf.len() + pad_len;
trace!(
"building: total size = {}+{}={} / {MAX_MESSAGE_PAYLOAD_LENGTH}",
buf.len(),
pad_len,
total_size,
);
if total_size >= MAX_MESSAGE_PAYLOAD_LENGTH {
Err(FrameError::InvalidPayloadLength(total_size))?
}
dst.put_u8(pt);
dst.put_u16(buf.len() as u16);
dst.put(buf);
if pad_len != 0 {
dst.put_bytes(0_u8, pad_len);
}
Ok(())
}