use super::{chunk_header::*, chunk_type::*, *};
use alloc::string::ToString;
#[derive(Default, Debug, Clone)]
pub(crate) struct ChunkForwardTsn {
pub(crate) new_cumulative_tsn: u32,
pub(crate) streams: Vec<ChunkForwardTsnStream>,
}
pub(crate) const NEW_CUMULATIVE_TSN_LENGTH: usize = 4;
pub(crate) const FORWARD_TSN_STREAM_LENGTH: usize = 4;
impl fmt::Display for ChunkForwardTsn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut res = vec![self.header().to_string()];
res.push(format!("New Cumulative TSN: {}", self.new_cumulative_tsn));
for s in &self.streams {
res.push(format!(" - si={}, ssn={}", s.identifier, s.sequence));
}
write!(f, "{}", res.join("\n"))
}
}
impl Chunk for ChunkForwardTsn {
fn header(&self) -> ChunkHeader {
ChunkHeader {
typ: CT_FORWARD_TSN,
flags: 0,
value_length: self.value_length() as u16,
}
}
fn unmarshal(buf: &Bytes) -> Result<Self> {
let header = ChunkHeader::unmarshal(buf)?;
if header.typ != CT_FORWARD_TSN {
return Err(Error::ErrChunkTypeNotForwardTsn);
}
if header.value_length() < NEW_CUMULATIVE_TSN_LENGTH {
return Err(Error::ErrChunkTooShort);
}
let mut offset = CHUNK_HEADER_SIZE + NEW_CUMULATIVE_TSN_LENGTH;
let reader = &mut buf.slice(CHUNK_HEADER_SIZE..CHUNK_HEADER_SIZE + header.value_length());
let new_cumulative_tsn = reader.get_u32();
let mut streams = vec![];
let value_end = CHUNK_HEADER_SIZE + header.value_length();
let mut remaining = value_end - offset;
while remaining > 0 {
let s = ChunkForwardTsnStream::unmarshal(&buf.slice(offset..value_end))?;
offset += s.value_length();
remaining -= s.value_length();
streams.push(s);
}
Ok(ChunkForwardTsn {
new_cumulative_tsn,
streams,
})
}
fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
self.header().marshal_to(writer)?;
writer.put_u32(self.new_cumulative_tsn);
for s in &self.streams {
writer.extend(s.marshal()?);
}
Ok(writer.len())
}
fn check(&self) -> Result<()> {
Ok(())
}
fn value_length(&self) -> usize {
NEW_CUMULATIVE_TSN_LENGTH + FORWARD_TSN_STREAM_LENGTH * self.streams.len()
}
fn as_any(&self) -> &(dyn Any + Send + Sync) {
self
}
}
#[derive(Debug, Clone)]
pub(crate) struct ChunkForwardTsnStream {
pub(crate) identifier: u16,
pub(crate) sequence: u16,
}
impl fmt::Display for ChunkForwardTsnStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}, {}", self.identifier, self.sequence)
}
}
impl Chunk for ChunkForwardTsnStream {
fn header(&self) -> ChunkHeader {
ChunkHeader {
typ: ChunkType(0),
flags: 0,
value_length: self.value_length() as u16,
}
}
fn unmarshal(buf: &Bytes) -> Result<Self> {
if buf.len() < FORWARD_TSN_STREAM_LENGTH {
return Err(Error::ErrChunkTooShort);
}
let reader = &mut buf.clone();
let identifier = reader.get_u16();
let sequence = reader.get_u16();
Ok(ChunkForwardTsnStream {
identifier,
sequence,
})
}
fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
writer.put_u16(self.identifier);
writer.put_u16(self.sequence);
Ok(writer.len())
}
fn check(&self) -> Result<()> {
Ok(())
}
fn value_length(&self) -> usize {
FORWARD_TSN_STREAM_LENGTH
}
fn as_any(&self) -> &(dyn Any + Send + Sync) {
self
}
}