use std::{cmp::min, io};
use bytes::{Bytes, BytesMut};
use speedy::{Context, Writable, Writer};
use byteorder::ReadBytesExt;
use log::warn;
use crate::RepresentationIdentifier;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct SerializedPayload {
pub representation_identifier: RepresentationIdentifier,
pub representation_options: [u8; 2],
pub value: Bytes,
}
const H_LEN: usize = 2 + 2;
impl SerializedPayload {
pub fn new(rep_id: RepresentationIdentifier, payload: Vec<u8>) -> Self {
Self {
representation_identifier: rep_id,
representation_options: [0, 0],
value: Bytes::from(payload),
}
}
pub fn new_from_bytes(rep_id: RepresentationIdentifier, payload: Bytes) -> Self {
Self {
representation_identifier: rep_id,
representation_options: [0, 0],
value: payload,
}
}
pub(crate) fn reallocate(&mut self) {
self.value = Bytes::copy_from_slice(&self.value);
}
pub fn len_serialized(&self) -> usize {
H_LEN + self.value.len()
}
pub fn bytes_slice(&self, from: usize, to_before: usize) -> Bytes {
let to_before = min(to_before, self.value.len() + H_LEN);
let from = min(from, to_before);
if from >= H_LEN {
self.value.slice(from - H_LEN..to_before - H_LEN)
} else {
let mut b = BytesMut::with_capacity(to_before);
b.extend_from_slice(&self.representation_identifier.bytes);
b.extend_from_slice(&self.representation_options);
assert_eq!(b.len(), H_LEN);
if to_before > H_LEN {
b.extend_from_slice(&self.value.slice(..to_before - H_LEN));
}
b.freeze().slice(from..to_before)
}
}
pub fn from_bytes(bytes: &Bytes) -> io::Result<Self> {
let mut reader = io::Cursor::new(&bytes);
let representation_identifier = RepresentationIdentifier {
bytes: [reader.read_u8()?, reader.read_u8()?],
};
let representation_options = [reader.read_u8()?, reader.read_u8()?];
let value = if bytes.len() >= H_LEN {
bytes.slice(H_LEN..)
} else {
warn!("DATA submessage was smaller than submessage header: {bytes:?}");
return Err(io::Error::new(
io::ErrorKind::Other,
"Too short DATA submessage.",
));
};
Ok(Self {
representation_identifier,
representation_options,
value,
})
}
}
impl<C: Context> Writable<C> for SerializedPayload {
fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
writer.write_u8(self.representation_identifier.bytes[0])?;
writer.write_u8(self.representation_identifier.bytes[1])?;
writer.write_u8(self.representation_options[0])?;
writer.write_u8(self.representation_options[1])?;
writer.write_bytes(&self.value)?;
Ok(())
}
}
impl From<SerializedPayload> for Bytes {
fn from(sp: SerializedPayload) -> Bytes {
let buf = sp.write_to_vec().unwrap(); buf.into()
}
}