bacnet_encoding/
segmentation.rs1use bacnet_types::error::Error;
8use bytes::Bytes;
9use std::collections::HashMap;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum SegmentedPduType {
16 ConfirmedRequest,
18 ComplexAck,
20}
21
22pub fn max_segment_payload(max_apdu_length: u16, pdu_type: SegmentedPduType) -> usize {
26 let overhead = match pdu_type {
27 SegmentedPduType::ConfirmedRequest => 6,
28 SegmentedPduType::ComplexAck => 5,
29 };
30 (max_apdu_length as usize).saturating_sub(overhead)
31}
32
33pub fn split_payload(payload: &[u8], max_segment_size: usize) -> Vec<Bytes> {
40 if max_segment_size == 0 || payload.is_empty() {
41 return vec![Bytes::copy_from_slice(payload)];
42 }
43 let segments: Vec<Bytes> = payload
44 .chunks(max_segment_size)
45 .map(Bytes::copy_from_slice)
46 .collect();
47 if segments.len() > 256 {
48 return vec![Bytes::copy_from_slice(payload)];
49 }
50 segments
51}
52
53pub struct SegmentReceiver {
58 segments: HashMap<u8, Bytes>,
59}
60
61impl Default for SegmentReceiver {
62 fn default() -> Self {
63 Self::new()
64 }
65}
66
67impl SegmentReceiver {
68 pub fn new() -> Self {
70 Self {
71 segments: HashMap::new(),
72 }
73 }
74
75 const MAX_SEGMENT_SIZE: usize = 1476;
77
78 pub fn receive(&mut self, sequence_number: u8, data: Bytes) -> Result<(), Error> {
82 if data.len() > Self::MAX_SEGMENT_SIZE {
83 return Err(Error::Segmentation(format!(
84 "segment size {} exceeds maximum {}",
85 data.len(),
86 Self::MAX_SEGMENT_SIZE
87 )));
88 }
89 self.segments.insert(sequence_number, data);
90 Ok(())
91 }
92
93 pub fn has_segment(&self, sequence_number: u8) -> bool {
95 self.segments.contains_key(&sequence_number)
96 }
97
98 pub fn received_count(&self) -> usize {
100 self.segments.len()
101 }
102
103 pub fn reassemble(&self, total_segments: usize) -> Result<Vec<u8>, Error> {
108 if total_segments > 256 {
109 return Err(Error::Segmentation(format!(
110 "total_segments {total_segments} exceeds maximum BACnet value (256)"
111 )));
112 }
113 let mut result = Vec::new();
114 for i in 0..total_segments {
115 let seq = i as u8;
116 match self.segments.get(&seq) {
117 Some(data) => result.extend_from_slice(data),
118 None => {
119 return Err(Error::Segmentation(format!(
120 "missing segment {} of {}",
121 i, total_segments
122 )));
123 }
124 }
125 }
126 Ok(result)
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn max_segment_payload_confirmed_request() {
136 assert_eq!(
137 max_segment_payload(480, SegmentedPduType::ConfirmedRequest),
138 474
139 );
140 assert_eq!(
141 max_segment_payload(1476, SegmentedPduType::ConfirmedRequest),
142 1470
143 );
144 }
145
146 #[test]
147 fn max_segment_payload_complex_ack() {
148 assert_eq!(max_segment_payload(480, SegmentedPduType::ComplexAck), 475);
149 assert_eq!(
150 max_segment_payload(1476, SegmentedPduType::ComplexAck),
151 1471
152 );
153 }
154
155 #[test]
156 fn split_payload_fits_single_segment() {
157 let payload = vec![0u8; 100];
158 let segments = split_payload(&payload, 200);
159 assert_eq!(segments.len(), 1);
160 assert_eq!(segments[0], payload);
161 }
162
163 #[test]
164 fn split_payload_exact_fit() {
165 let payload = vec![0u8; 200];
166 let segments = split_payload(&payload, 100);
167 assert_eq!(segments.len(), 2);
168 assert_eq!(segments[0].len(), 100);
169 assert_eq!(segments[1].len(), 100);
170 }
171
172 #[test]
173 fn split_payload_remainder() {
174 let payload = vec![0u8; 250];
175 let segments = split_payload(&payload, 100);
176 assert_eq!(segments.len(), 3);
177 assert_eq!(segments[0].len(), 100);
178 assert_eq!(segments[1].len(), 100);
179 assert_eq!(segments[2].len(), 50);
180 }
181
182 #[test]
183 fn split_empty_payload() {
184 let segments = split_payload(&[], 100);
185 assert_eq!(segments.len(), 1);
186 assert!(segments[0].is_empty());
187 }
188
189 #[test]
190 fn reassemble_ordered_segments() {
191 let original = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
192 let segments = split_payload(&original, 3);
193 assert_eq!(segments.len(), 4); let mut receiver = SegmentReceiver::new();
196 for (i, seg) in segments.iter().enumerate() {
197 receiver.receive(i as u8, seg.clone()).unwrap();
198 }
199 let reassembled = receiver.reassemble(segments.len()).unwrap();
200 assert_eq!(reassembled, original);
201 }
202
203 #[test]
204 fn reassemble_out_of_order() {
205 let mut receiver = SegmentReceiver::new();
206 receiver.receive(2, Bytes::from_static(&[5, 6])).unwrap();
207 receiver.receive(0, Bytes::from_static(&[1, 2])).unwrap();
208 receiver.receive(1, Bytes::from_static(&[3, 4])).unwrap();
209 let reassembled = receiver.reassemble(3).unwrap();
210 assert_eq!(reassembled, vec![1, 2, 3, 4, 5, 6]);
211 }
212
213 #[test]
214 fn reassemble_missing_segment_fails() {
215 let mut receiver = SegmentReceiver::new();
216 receiver.receive(0, Bytes::from_static(&[1, 2])).unwrap();
217 receiver.receive(2, Bytes::from_static(&[5, 6])).unwrap();
219 assert!(receiver.reassemble(3).is_err());
220 }
221
222 #[test]
223 fn split_payload_zero_segment_size() {
224 let result = split_payload(&[1, 2, 3], 0);
226 assert_eq!(result, vec![vec![1, 2, 3]]);
227 }
228}