pim_protocol/
fragment_frame.rs1pub const MAX_FRAGMENT_PAYLOAD: usize = 1200;
17
18pub const FRAGMENT_HEADER_SIZE: usize = 8;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct FragmentFrame {
24 pub fragment_id: u32,
27 pub fragment_offset: u16,
29 pub total_length: u16,
31 pub payload: bytes::Bytes,
33}
34
35impl FragmentFrame {
36 pub fn serialize(&self) -> Vec<u8> {
38 let mut buf = Vec::with_capacity(FRAGMENT_HEADER_SIZE + self.payload.len());
39 buf.extend_from_slice(&self.fragment_id.to_be_bytes());
40 buf.extend_from_slice(&self.fragment_offset.to_be_bytes());
41 buf.extend_from_slice(&self.total_length.to_be_bytes());
42 buf.extend_from_slice(&self.payload);
43 buf
44 }
45
46 pub fn deserialize(buf: &[u8]) -> Option<Self> {
49 if buf.len() < FRAGMENT_HEADER_SIZE {
50 return None;
51 }
52 let fragment_id = u32::from_be_bytes(buf[0..4].try_into().ok()?);
53 let fragment_offset = u16::from_be_bytes(buf[4..6].try_into().ok()?);
54 let total_length = u16::from_be_bytes(buf[6..8].try_into().ok()?);
55 let payload = bytes::Bytes::copy_from_slice(&buf[8..]);
56
57 let end = (fragment_offset as usize).checked_add(payload.len())?;
59 if end > total_length as usize {
60 return None;
61 }
62
63 Some(Self {
64 fragment_id,
65 fragment_offset,
66 total_length,
67 payload,
68 })
69 }
70
71 pub fn is_last(&self) -> bool {
74 self.fragment_offset as usize + self.payload.len() == self.total_length as usize
75 }
76}
77
78pub fn fragment_packet(data: bytes::Bytes, fragment_id: u32) -> Vec<FragmentFrame> {
83 if data.is_empty() {
84 return Vec::new();
85 }
86
87 let total_length = data.len() as u16;
88 let mut frames = Vec::with_capacity(data.len().div_ceil(MAX_FRAGMENT_PAYLOAD));
89 let mut offset = 0usize;
90
91 while offset < data.len() {
92 let end = (offset + MAX_FRAGMENT_PAYLOAD).min(data.len());
93 frames.push(FragmentFrame {
94 fragment_id,
95 fragment_offset: offset as u16,
96 total_length,
97 payload: data.slice(offset..end),
98 });
99 offset = end;
100 }
101
102 frames
103}
104
105#[cfg(test)]
108mod tests;