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