use std::io;
use log::debug;
use speedy::{Context, Error, Readable, Writable, Writer};
use enumflags2::BitFlags;
use bytes::Bytes;
use crate::{
messages::submessages::{
submessage_elements::{parameter_list::ParameterList, serialized_payload::SerializedPayload},
submessages::*,
},
structure::{
guid::EntityId,
sequence_number::{FragmentNumber, SequenceNumber},
},
};
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(test, derive(Default))]
pub struct DataFrag {
pub reader_id: EntityId,
pub writer_id: EntityId,
pub writer_sn: SequenceNumber,
pub fragment_starting_num: FragmentNumber,
pub fragments_in_submessage: u16,
pub data_size: u32,
pub fragment_size: u16,
pub inline_qos: Option<ParameterList>,
pub serialized_payload: SerializedPayload,
}
impl<'a> DataFrag {
pub fn deserialize(buffer: &Bytes, flags: BitFlags<DATAFRAG_Flags>) -> io::Result<Self> {
let mut cursor = io::Cursor::new(&buffer);
let endianness = endianness_flag(flags.bits());
let map_speedy_err = |p: Error| io::Error::new(io::ErrorKind::Other, p);
let _extra_flags =
u16::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor).map_err(map_speedy_err)?;
let octets_to_inline_qos =
u16::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor).map_err(map_speedy_err)?;
let reader_id = EntityId::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor)
.map_err(map_speedy_err)?;
let writer_id = EntityId::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor)
.map_err(map_speedy_err)?;
let writer_sn = SequenceNumber::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor)
.map_err(map_speedy_err)?;
let fragment_starting_num =
FragmentNumber::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor)
.map_err(map_speedy_err)?;
let fragments_in_submessage =
u16::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor).map_err(map_speedy_err)?;
let fragment_size =
u16::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor).map_err(map_speedy_err)?;
let data_size =
u32::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor).map_err(map_speedy_err)?;
let expect_qos = flags.contains(DATAFRAG_Flags::InlineQos);
let rtps_v23_header_size: u16 = 7 * 4;
let extra_octets = octets_to_inline_qos - rtps_v23_header_size;
if octets_to_inline_qos < rtps_v23_header_size {
return Err(io::Error::new(
io::ErrorKind::Other,
"DataFrag has too low octetsToInlineQos",
));
}
cursor.set_position(cursor.position() + u64::from(extra_octets));
let inline_qos = if expect_qos {
Some(
ParameterList::read_from_stream_unbuffered_with_ctx(endianness, &mut cursor)
.map_err(map_speedy_err)?,
)
} else {
None
};
let serialized_payload =
SerializedPayload::from_bytes(&buffer.clone().split_off(cursor.position() as usize))?;
Ok(Self {
reader_id,
writer_id,
writer_sn,
fragment_starting_num,
fragments_in_submessage,
data_size,
fragment_size,
inline_qos,
serialized_payload,
})
}
}
impl<C: Context> Writable<C> for DataFrag {
fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
writer.write_u16(0)?;
if self.inline_qos.is_some() && !self.inline_qos.as_ref().unwrap().parameters.is_empty() {
debug!("self.inline_qos {:?}", self.inline_qos);
todo!()
} else if self.inline_qos.is_some() && self.inline_qos.as_ref().unwrap().parameters.is_empty()
|| self.inline_qos.is_none()
{
writer.write_u16(24)?;
}
writer.write_value(&self.reader_id)?;
writer.write_value(&self.writer_id)?;
writer.write_value(&self.writer_sn)?;
writer.write_value(&self.fragment_starting_num)?;
writer.write_value(&self.fragments_in_submessage)?;
writer.write_value(&self.fragment_size)?;
writer.write_value(&self.data_size)?;
if self.inline_qos.is_some() && !self.inline_qos.as_ref().unwrap().parameters.is_empty() {
writer.write_value(&self.inline_qos)?;
}
writer.write_value(&self.serialized_payload)?;
Ok(())
}
}