1use bacnet_types::error::Error;
8use bytes::Bytes;
9use std::collections::HashMap;
10
11pub fn duplicate_in_window(
20 sequence_number: u8,
21 initial_sequence_number: u8,
22 last_sequence_number: u8,
23) -> bool {
24 let received_count = last_sequence_number.wrapping_sub(initial_sequence_number);
25 received_count != 0 && sequence_number.wrapping_sub(initial_sequence_number) <= received_count
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum SegmentedPduType {
33 ConfirmedRequest,
35 ComplexAck,
37}
38
39pub fn max_segment_payload(max_apdu_length: u16, pdu_type: SegmentedPduType) -> usize {
43 let overhead = match pdu_type {
44 SegmentedPduType::ConfirmedRequest => 6,
45 SegmentedPduType::ComplexAck => 5,
46 };
47 (max_apdu_length as usize).saturating_sub(overhead)
48}
49
50pub fn split_payload(payload: &[u8], max_segment_size: usize) -> Result<Vec<Bytes>, Error> {
58 if max_segment_size == 0 {
59 return Err(Error::Segmentation(
60 "payload cannot be segmented with max segment size 0".into(),
61 ));
62 }
63 if payload.is_empty() {
64 return Ok(vec![Bytes::new()]);
65 }
66 let segments: Vec<Bytes> = payload
67 .chunks(max_segment_size)
68 .map(Bytes::copy_from_slice)
69 .collect();
70 if segments.len() > 256 {
71 return Err(Error::Segmentation(format!(
72 "payload requires {} segments, maximum is 256",
73 segments.len()
74 )));
75 }
76 Ok(segments)
77}
78
79pub struct SegmentReceiver {
84 segments: HashMap<u8, Bytes>,
85}
86
87impl Default for SegmentReceiver {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93impl SegmentReceiver {
94 pub fn new() -> Self {
96 Self {
97 segments: HashMap::new(),
98 }
99 }
100
101 const MAX_SEGMENT_SIZE: usize = 1476;
103
104 pub fn receive(&mut self, sequence_number: u8, data: Bytes) -> Result<(), Error> {
108 if data.len() > Self::MAX_SEGMENT_SIZE {
109 return Err(Error::Segmentation(format!(
110 "segment size {} exceeds maximum {}",
111 data.len(),
112 Self::MAX_SEGMENT_SIZE
113 )));
114 }
115 self.segments.insert(sequence_number, data);
116 Ok(())
117 }
118
119 pub fn has_segment(&self, sequence_number: u8) -> bool {
121 self.segments.contains_key(&sequence_number)
122 }
123
124 pub fn received_count(&self) -> usize {
126 self.segments.len()
127 }
128
129 pub fn reassemble(&self, total_segments: usize) -> Result<Vec<u8>, Error> {
134 if total_segments > 256 {
135 return Err(Error::Segmentation(format!(
136 "total_segments {total_segments} exceeds maximum BACnet value (256)"
137 )));
138 }
139 let mut result = Vec::with_capacity(total_segments * 480);
140 for i in 0..total_segments {
141 let seq = i as u8;
142 match self.segments.get(&seq) {
143 Some(data) => result.extend_from_slice(data),
144 None => {
145 return Err(Error::Segmentation(format!(
146 "missing segment {} of {}",
147 i, total_segments
148 )));
149 }
150 }
151 }
152 Ok(result)
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn max_segment_payload_confirmed_request() {
162 assert_eq!(
163 max_segment_payload(480, SegmentedPduType::ConfirmedRequest),
164 474
165 );
166 assert_eq!(
167 max_segment_payload(1476, SegmentedPduType::ConfirmedRequest),
168 1470
169 );
170 }
171
172 #[test]
173 fn duplicate_in_window_matches_addendum_examples() {
174 assert!(duplicate_in_window(0, 0, 1));
175 assert!(duplicate_in_window(1, 0, 1));
176 assert!(!duplicate_in_window(2, 0, 1));
177 assert!(!duplicate_in_window(3, 0, 1));
178 }
179
180 #[test]
181 fn duplicate_in_window_is_false_before_current_window_receives_a_segment() {
182 assert!(!duplicate_in_window(0, 0, 0));
183 assert!(!duplicate_in_window(255, 0, 0));
184 }
185
186 #[test]
187 fn duplicate_in_window_uses_modulo_256_arithmetic() {
188 assert!(duplicate_in_window(255, 254, 0));
189 assert!(duplicate_in_window(0, 254, 0));
190 assert!(!duplicate_in_window(1, 254, 0));
191 }
192
193 #[test]
194 fn duplicate_in_window_does_not_apply_ordinary_sequence_ordering() {
195 assert!(duplicate_in_window(255, 250, 2));
196 assert!(duplicate_in_window(1, 250, 2));
197 assert!(!duplicate_in_window(249, 250, 2));
198 assert!(!duplicate_in_window(3, 250, 2));
199 }
200
201 #[test]
202 fn max_segment_payload_complex_ack() {
203 assert_eq!(max_segment_payload(480, SegmentedPduType::ComplexAck), 475);
204 assert_eq!(
205 max_segment_payload(1476, SegmentedPduType::ComplexAck),
206 1471
207 );
208 }
209
210 #[test]
211 fn split_payload_fits_single_segment() {
212 let payload = vec![0u8; 100];
213 let segments = split_payload(&payload, 200).unwrap();
214 assert_eq!(segments.len(), 1);
215 assert_eq!(segments[0], payload);
216 }
217
218 #[test]
219 fn split_payload_exact_fit() {
220 let payload = vec![0u8; 200];
221 let segments = split_payload(&payload, 100).unwrap();
222 assert_eq!(segments.len(), 2);
223 assert_eq!(segments[0].len(), 100);
224 assert_eq!(segments[1].len(), 100);
225 }
226
227 #[test]
228 fn split_payload_remainder() {
229 let payload = vec![0u8; 250];
230 let segments = split_payload(&payload, 100).unwrap();
231 assert_eq!(segments.len(), 3);
232 assert_eq!(segments[0].len(), 100);
233 assert_eq!(segments[1].len(), 100);
234 assert_eq!(segments[2].len(), 50);
235 }
236
237 #[test]
238 fn split_empty_payload() {
239 let segments = split_payload(&[], 100).unwrap();
240 assert_eq!(segments.len(), 1);
241 assert!(segments[0].is_empty());
242 }
243
244 #[test]
250 fn split_empty_payload_zero_segment_size_errors() {
251 assert!(split_payload(&[], 0).is_err());
252 }
253
254 #[test]
255 fn reassemble_ordered_segments() {
256 let original = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
257 let segments = split_payload(&original, 3).unwrap();
258 assert_eq!(segments.len(), 4); let mut receiver = SegmentReceiver::new();
261 for (i, seg) in segments.iter().enumerate() {
262 receiver.receive(i as u8, seg.clone()).unwrap();
263 }
264 let reassembled = receiver.reassemble(segments.len()).unwrap();
265 assert_eq!(reassembled, original);
266 }
267
268 #[test]
269 fn reassemble_out_of_order() {
270 let mut receiver = SegmentReceiver::new();
271 receiver.receive(2, Bytes::from_static(&[5, 6])).unwrap();
272 receiver.receive(0, Bytes::from_static(&[1, 2])).unwrap();
273 receiver.receive(1, Bytes::from_static(&[3, 4])).unwrap();
274 let reassembled = receiver.reassemble(3).unwrap();
275 assert_eq!(reassembled, vec![1, 2, 3, 4, 5, 6]);
276 }
277
278 #[test]
279 fn reassemble_missing_segment_fails() {
280 let mut receiver = SegmentReceiver::new();
281 receiver.receive(0, Bytes::from_static(&[1, 2])).unwrap();
282 receiver.receive(2, Bytes::from_static(&[5, 6])).unwrap();
284 assert!(receiver.reassemble(3).is_err());
285 }
286
287 #[test]
288 fn split_payload_zero_segment_size() {
289 assert!(split_payload(&[1, 2, 3], 0).is_err());
290 }
291
292 #[test]
293 fn split_payload_over_256_segments_errors() {
294 let payload = vec![0u8; 257];
295 assert!(split_payload(&payload, 1).is_err());
296 }
297}