#[derive(Debug)]
pub struct PacketPackager {
max_packet_size: usize,
last_id: std::sync::atomic::AtomicU64,
}
impl PacketPackager {
pub fn new(mtu: u16) -> Self {
Self {
max_packet_size: mtu as usize,
last_id: std::sync::atomic::AtomicU64::new(1),
}
}
pub fn package(&self, data: bytes::Bytes, property: crate::packet::Property, sequence: &std::sync::atomic::AtomicU16) -> Vec<crate::packet::Packet> {
let header_len = if property.is_sequenced() { 3 } else { 1 };
if data.len() + header_len > self.max_packet_size {
let fragment_id = self.last_id.fetch_add(1, super::ATOMIC_ORDERING);
let fragment_id_u16 = (fragment_id & 0xFFFF) as u16;
let chunk_size = self.max_packet_size - (header_len + crate::packet::Fragment::SIZE);
let total_chunks = ((data.len() as f64)/(chunk_size as f64)).ceil() as usize;
if total_chunks > u16::MAX as usize {
panic!("Too much data to chunk");
}
let total_chunks_u16 = total_chunks as u16;
data.chunks(chunk_size).enumerate().map(|(i, chunk)| {
let global_sequence = if property.is_sequenced() {
sequence.fetch_add(1, super::ATOMIC_ORDERING) % 32768
} else {
0
};
crate::packet::Packet {
header: crate::packet::Header {
property,
sequence: Some(global_sequence),
fragment: Some(crate::packet::Fragment {
id: fragment_id_u16,
part: i as u16,
total: total_chunks_u16,
}),
},
data: bytes::Bytes::copy_from_slice(chunk)
}
}).collect()
} else {
let sequence = if property.is_sequenced() {
Some(sequence.fetch_add(1, super::ATOMIC_ORDERING) % 32768)
} else {
None
};
vec![
crate::packet::Packet {
header: crate::packet::Header {
property,
sequence,
fragment: None,
},
data,
}
]
}
}
}