smoltcp/storage/
assembler.rs

1use core::fmt;
2
3use crate::config::ASSEMBLER_MAX_SEGMENT_COUNT;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct TooManyHolesError;
7
8impl fmt::Display for TooManyHolesError {
9    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
10        write!(f, "too many holes")
11    }
12}
13
14#[cfg(feature = "std")]
15impl std::error::Error for TooManyHolesError {}
16
17/// A contiguous chunk of absent data, followed by a contiguous chunk of present data.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19struct Contig {
20    hole_size: usize,
21    data_size: usize,
22}
23
24impl fmt::Display for Contig {
25    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26        if self.has_hole() {
27            write!(f, "({})", self.hole_size)?;
28        }
29        if self.has_hole() && self.has_data() {
30            write!(f, " ")?;
31        }
32        if self.has_data() {
33            write!(f, "{}", self.data_size)?;
34        }
35        Ok(())
36    }
37}
38
39#[cfg(feature = "defmt")]
40impl defmt::Format for Contig {
41    fn format(&self, fmt: defmt::Formatter) {
42        if self.has_hole() {
43            defmt::write!(fmt, "({})", self.hole_size);
44        }
45        if self.has_hole() && self.has_data() {
46            defmt::write!(fmt, " ");
47        }
48        if self.has_data() {
49            defmt::write!(fmt, "{}", self.data_size);
50        }
51    }
52}
53
54impl Contig {
55    const fn empty() -> Contig {
56        Contig {
57            hole_size: 0,
58            data_size: 0,
59        }
60    }
61
62    fn hole_and_data(hole_size: usize, data_size: usize) -> Contig {
63        Contig {
64            hole_size,
65            data_size,
66        }
67    }
68
69    fn has_hole(&self) -> bool {
70        self.hole_size != 0
71    }
72
73    fn has_data(&self) -> bool {
74        self.data_size != 0
75    }
76
77    fn total_size(&self) -> usize {
78        self.hole_size + self.data_size
79    }
80
81    fn shrink_hole_by(&mut self, size: usize) {
82        self.hole_size -= size;
83    }
84
85    fn shrink_hole_to(&mut self, size: usize) {
86        debug_assert!(self.hole_size >= size);
87
88        let total_size = self.total_size();
89        self.hole_size = size;
90        self.data_size = total_size - size;
91    }
92}
93
94/// A buffer (re)assembler.
95///
96/// Currently, up to a hardcoded limit of 4 or 32 holes can be tracked in the buffer.
97#[derive(Debug, PartialEq, Eq, Clone)]
98pub struct Assembler {
99    contigs: [Contig; ASSEMBLER_MAX_SEGMENT_COUNT],
100}
101
102impl fmt::Display for Assembler {
103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104        write!(f, "[ ")?;
105        for contig in self.contigs.iter() {
106            if !contig.has_data() {
107                break;
108            }
109            write!(f, "{contig} ")?;
110        }
111        write!(f, "]")?;
112        Ok(())
113    }
114}
115
116#[cfg(feature = "defmt")]
117impl defmt::Format for Assembler {
118    fn format(&self, fmt: defmt::Formatter) {
119        defmt::write!(fmt, "[ ");
120        for contig in self.contigs.iter() {
121            if !contig.has_data() {
122                break;
123            }
124            defmt::write!(fmt, "{} ", contig);
125        }
126        defmt::write!(fmt, "]");
127    }
128}
129
130// Invariant on Assembler::contigs:
131// - There's an index `i` where all contigs before have data, and all contigs after don't (are unused).
132// - All contigs with data must have hole_size != 0, except the first.
133
134impl Assembler {
135    /// Create a new buffer assembler.
136    pub const fn new() -> Assembler {
137        const EMPTY: Contig = Contig::empty();
138        Assembler {
139            contigs: [EMPTY; ASSEMBLER_MAX_SEGMENT_COUNT],
140        }
141    }
142
143    pub fn clear(&mut self) {
144        self.contigs.fill(Contig::empty());
145    }
146
147    fn front(&self) -> Contig {
148        self.contigs[0]
149    }
150
151    /// Return length of the front contiguous range without removing it from the assembler
152    pub fn peek_front(&self) -> usize {
153        let front = self.front();
154        if front.has_hole() {
155            0
156        } else {
157            front.data_size
158        }
159    }
160
161    fn back(&self) -> Contig {
162        self.contigs[self.contigs.len() - 1]
163    }
164
165    /// Return whether the assembler contains no data.
166    pub fn is_empty(&self) -> bool {
167        !self.front().has_data()
168    }
169
170    /// Remove a contig at the given index.
171    fn remove_contig_at(&mut self, at: usize) {
172        debug_assert!(self.contigs[at].has_data());
173
174        for i in at..self.contigs.len() - 1 {
175            if !self.contigs[i].has_data() {
176                return;
177            }
178            self.contigs[i] = self.contigs[i + 1];
179        }
180
181        // Removing the last one.
182        self.contigs[self.contigs.len() - 1] = Contig::empty();
183    }
184
185    /// Add a contig at the given index, and return a pointer to it.
186    fn add_contig_at(&mut self, at: usize) -> Result<&mut Contig, TooManyHolesError> {
187        if self.back().has_data() {
188            return Err(TooManyHolesError);
189        }
190
191        for i in (at + 1..self.contigs.len()).rev() {
192            self.contigs[i] = self.contigs[i - 1];
193        }
194
195        self.contigs[at] = Contig::empty();
196        Ok(&mut self.contigs[at])
197    }
198
199    /// Add a new contiguous range to the assembler,
200    /// or return `Err(TooManyHolesError)` if too many discontinuities are already recorded.
201    pub fn add(&mut self, mut offset: usize, size: usize) -> Result<(), TooManyHolesError> {
202        if size == 0 {
203            return Ok(());
204        }
205
206        let mut i = 0;
207
208        // Find index of the contig containing the start of the range.
209        loop {
210            if i == self.contigs.len() {
211                // The new range is after all the previous ranges, but there/s no space to add it.
212                return Err(TooManyHolesError);
213            }
214            let contig = &mut self.contigs[i];
215            if !contig.has_data() {
216                // The new range is after all the previous ranges. Add it.
217                *contig = Contig::hole_and_data(offset, size);
218                return Ok(());
219            }
220            if offset <= contig.total_size() {
221                break;
222            }
223            offset -= contig.total_size();
224            i += 1;
225        }
226
227        let contig = &mut self.contigs[i];
228        if offset < contig.hole_size {
229            // Range starts within the hole.
230
231            if offset + size < contig.hole_size {
232                // Range also ends within the hole.
233                let new_contig = self.add_contig_at(i)?;
234                new_contig.hole_size = offset;
235                new_contig.data_size = size;
236
237                // Previous contigs[index] got moved to contigs[index+1]
238                self.contigs[i + 1].shrink_hole_by(offset + size);
239                return Ok(());
240            }
241
242            // The range being added covers both a part of the hole and a part of the data
243            // in this contig, shrink the hole in this contig.
244            contig.shrink_hole_to(offset);
245        }
246
247        // coalesce contigs to the right.
248        let mut j = i + 1;
249        while j < self.contigs.len()
250            && self.contigs[j].has_data()
251            && offset + size >= self.contigs[i].total_size() + self.contigs[j].hole_size
252        {
253            self.contigs[i].data_size += self.contigs[j].total_size();
254            j += 1;
255        }
256        let shift = j - i - 1;
257        if shift != 0 {
258            for x in i + 1..self.contigs.len() {
259                if !self.contigs[x].has_data() {
260                    break;
261                }
262
263                self.contigs[x] = self
264                    .contigs
265                    .get(x + shift)
266                    .copied()
267                    .unwrap_or_else(Contig::empty);
268            }
269        }
270
271        if offset + size > self.contigs[i].total_size() {
272            // The added range still extends beyond the current contig. Increase data size.
273            let left = offset + size - self.contigs[i].total_size();
274            self.contigs[i].data_size += left;
275
276            // Decrease hole size of the next, if any.
277            if i + 1 < self.contigs.len() && self.contigs[i + 1].has_data() {
278                self.contigs[i + 1].hole_size -= left;
279            }
280        }
281
282        Ok(())
283    }
284
285    /// Remove a contiguous range from the front of the assembler.
286    /// If no such range, return 0.
287    pub fn remove_front(&mut self) -> usize {
288        let front = self.front();
289        if front.has_hole() || !front.has_data() {
290            0
291        } else {
292            self.remove_contig_at(0);
293            debug_assert!(front.data_size > 0);
294            front.data_size
295        }
296    }
297
298    /// Add a segment, then remove_front.
299    ///
300    /// This is equivalent to calling `add` then `remove_front` individually,
301    /// except it's guaranteed to not fail when offset = 0.
302    /// This is required for TCP: we must never drop the next expected segment, or
303    /// the protocol might get stuck.
304    pub fn add_then_remove_front(
305        &mut self,
306        offset: usize,
307        size: usize,
308    ) -> Result<usize, TooManyHolesError> {
309        // This is the only case where a segment at offset=0 would cause the
310        // total amount of contigs to rise (and therefore can potentially cause
311        // a TooManyHolesError). Handle it in a way that is guaranteed to succeed.
312        if offset == 0 && size < self.contigs[0].hole_size {
313            self.contigs[0].hole_size -= size;
314            return Ok(size);
315        }
316
317        self.add(offset, size)?;
318        Ok(self.remove_front())
319    }
320
321    /// Iterate over all of the contiguous data ranges.
322    ///
323    /// This is used in calculating what data ranges have been received. The offset indicates the
324    /// number of bytes of contiguous data received before the beginnings of this Assembler.
325    ///
326    ///    Data        Hole        Data
327    /// |--- 100 ---|--- 200 ---|--- 100 ---|
328    ///
329    /// An offset of 1500 would return the ranges: ``(1500, 1600), (1800, 1900)``
330    pub fn iter_data(&self, first_offset: usize) -> AssemblerIter {
331        AssemblerIter::new(self, first_offset)
332    }
333}
334
335pub struct AssemblerIter<'a> {
336    assembler: &'a Assembler,
337    offset: usize,
338    index: usize,
339    left: usize,
340    right: usize,
341}
342
343impl<'a> AssemblerIter<'a> {
344    fn new(assembler: &'a Assembler, offset: usize) -> AssemblerIter<'a> {
345        AssemblerIter {
346            assembler,
347            offset,
348            index: 0,
349            left: 0,
350            right: 0,
351        }
352    }
353}
354
355impl<'a> Iterator for AssemblerIter<'a> {
356    type Item = (usize, usize);
357
358    fn next(&mut self) -> Option<(usize, usize)> {
359        let mut data_range = None;
360        while data_range.is_none() && self.index < self.assembler.contigs.len() {
361            let contig = self.assembler.contigs[self.index];
362            self.left += contig.hole_size;
363            self.right = self.left + contig.data_size;
364            data_range = if self.left < self.right {
365                let data_range = (self.left + self.offset, self.right + self.offset);
366                self.left = self.right;
367                Some(data_range)
368            } else {
369                None
370            };
371            self.index += 1;
372        }
373        data_range
374    }
375}
376
377#[cfg(test)]
378mod test {
379    use super::*;
380    use std::vec::Vec;
381
382    impl From<Vec<(usize, usize)>> for Assembler {
383        fn from(vec: Vec<(usize, usize)>) -> Assembler {
384            const EMPTY: Contig = Contig::empty();
385
386            let mut contigs = [EMPTY; ASSEMBLER_MAX_SEGMENT_COUNT];
387            for (i, &(hole_size, data_size)) in vec.iter().enumerate() {
388                contigs[i] = Contig {
389                    hole_size,
390                    data_size,
391                };
392            }
393            Assembler { contigs }
394        }
395    }
396
397    macro_rules! contigs {
398        [$( $x:expr ),*] => ({
399            Assembler::from(vec![$( $x ),*])
400        })
401    }
402
403    #[test]
404    fn test_new() {
405        let assr = Assembler::new();
406        assert_eq!(assr, contigs![]);
407    }
408
409    #[test]
410    fn test_empty_add_full() {
411        let mut assr = Assembler::new();
412        assert_eq!(assr.add(0, 16), Ok(()));
413        assert_eq!(assr, contigs![(0, 16)]);
414    }
415
416    #[test]
417    fn test_empty_add_front() {
418        let mut assr = Assembler::new();
419        assert_eq!(assr.add(0, 4), Ok(()));
420        assert_eq!(assr, contigs![(0, 4)]);
421    }
422
423    #[test]
424    fn test_empty_add_back() {
425        let mut assr = Assembler::new();
426        assert_eq!(assr.add(12, 4), Ok(()));
427        assert_eq!(assr, contigs![(12, 4)]);
428    }
429
430    #[test]
431    fn test_empty_add_mid() {
432        let mut assr = Assembler::new();
433        assert_eq!(assr.add(4, 8), Ok(()));
434        assert_eq!(assr, contigs![(4, 8)]);
435    }
436
437    #[test]
438    fn test_partial_add_front() {
439        let mut assr = contigs![(4, 8)];
440        assert_eq!(assr.add(0, 4), Ok(()));
441        assert_eq!(assr, contigs![(0, 12)]);
442    }
443
444    #[test]
445    fn test_partial_add_back() {
446        let mut assr = contigs![(4, 8)];
447        assert_eq!(assr.add(12, 4), Ok(()));
448        assert_eq!(assr, contigs![(4, 12)]);
449    }
450
451    #[test]
452    fn test_partial_add_front_overlap() {
453        let mut assr = contigs![(4, 8)];
454        assert_eq!(assr.add(0, 8), Ok(()));
455        assert_eq!(assr, contigs![(0, 12)]);
456    }
457
458    #[test]
459    fn test_partial_add_front_overlap_split() {
460        let mut assr = contigs![(4, 8)];
461        assert_eq!(assr.add(2, 6), Ok(()));
462        assert_eq!(assr, contigs![(2, 10)]);
463    }
464
465    #[test]
466    fn test_partial_add_back_overlap() {
467        let mut assr = contigs![(4, 8)];
468        assert_eq!(assr.add(8, 8), Ok(()));
469        assert_eq!(assr, contigs![(4, 12)]);
470    }
471
472    #[test]
473    fn test_partial_add_back_overlap_split() {
474        let mut assr = contigs![(4, 8)];
475        assert_eq!(assr.add(10, 4), Ok(()));
476        assert_eq!(assr, contigs![(4, 10)]);
477    }
478
479    #[test]
480    fn test_partial_add_both_overlap() {
481        let mut assr = contigs![(4, 8)];
482        assert_eq!(assr.add(0, 16), Ok(()));
483        assert_eq!(assr, contigs![(0, 16)]);
484    }
485
486    #[test]
487    fn test_partial_add_both_overlap_split() {
488        let mut assr = contigs![(4, 8)];
489        assert_eq!(assr.add(2, 12), Ok(()));
490        assert_eq!(assr, contigs![(2, 12)]);
491    }
492
493    #[test]
494    fn test_rejected_add_keeps_state() {
495        let mut assr = Assembler::new();
496        for c in 1..=ASSEMBLER_MAX_SEGMENT_COUNT {
497            assert_eq!(assr.add(c * 10, 3), Ok(()));
498        }
499        // Maximum of allowed holes is reached
500        let assr_before = assr.clone();
501        assert_eq!(assr.add(1, 3), Err(TooManyHolesError));
502        assert_eq!(assr_before, assr);
503    }
504
505    #[test]
506    fn test_empty_remove_front() {
507        let mut assr = contigs![];
508        assert_eq!(assr.remove_front(), 0);
509    }
510
511    #[test]
512    fn test_trailing_hole_remove_front() {
513        let mut assr = contigs![(0, 4)];
514        assert_eq!(assr.remove_front(), 4);
515        assert_eq!(assr, contigs![]);
516    }
517
518    #[test]
519    fn test_trailing_data_remove_front() {
520        let mut assr = contigs![(0, 4), (4, 4)];
521        assert_eq!(assr.remove_front(), 4);
522        assert_eq!(assr, contigs![(4, 4)]);
523    }
524
525    #[test]
526    fn test_boundary_case_remove_front() {
527        let mut vec = vec![(1, 1); ASSEMBLER_MAX_SEGMENT_COUNT];
528        vec[0] = (0, 2);
529        let mut assr = Assembler::from(vec);
530        assert_eq!(assr.remove_front(), 2);
531        let mut vec = vec![(1, 1); ASSEMBLER_MAX_SEGMENT_COUNT];
532        vec[ASSEMBLER_MAX_SEGMENT_COUNT - 1] = (0, 0);
533        let exp_assr = Assembler::from(vec);
534        assert_eq!(assr, exp_assr);
535    }
536
537    #[test]
538    fn test_shrink_next_hole() {
539        let mut assr = Assembler::new();
540        assert_eq!(assr.add(100, 10), Ok(()));
541        assert_eq!(assr.add(50, 10), Ok(()));
542        assert_eq!(assr.add(40, 30), Ok(()));
543        assert_eq!(assr, contigs![(40, 30), (30, 10)]);
544    }
545
546    #[test]
547    fn test_join_two() {
548        let mut assr = Assembler::new();
549        assert_eq!(assr.add(10, 10), Ok(()));
550        assert_eq!(assr.add(50, 10), Ok(()));
551        assert_eq!(assr.add(15, 40), Ok(()));
552        assert_eq!(assr, contigs![(10, 50)]);
553    }
554
555    #[test]
556    fn test_join_two_reversed() {
557        let mut assr = Assembler::new();
558        assert_eq!(assr.add(50, 10), Ok(()));
559        assert_eq!(assr.add(10, 10), Ok(()));
560        assert_eq!(assr.add(15, 40), Ok(()));
561        assert_eq!(assr, contigs![(10, 50)]);
562    }
563
564    #[test]
565    fn test_join_two_overlong() {
566        let mut assr = Assembler::new();
567        assert_eq!(assr.add(50, 10), Ok(()));
568        assert_eq!(assr.add(10, 10), Ok(()));
569        assert_eq!(assr.add(15, 60), Ok(()));
570        assert_eq!(assr, contigs![(10, 65)]);
571    }
572
573    #[test]
574    fn test_iter_empty() {
575        let assr = Assembler::new();
576        let segments: Vec<_> = assr.iter_data(10).collect();
577        assert_eq!(segments, vec![]);
578    }
579
580    #[test]
581    fn test_iter_full() {
582        let mut assr = Assembler::new();
583        assert_eq!(assr.add(0, 16), Ok(()));
584        let segments: Vec<_> = assr.iter_data(10).collect();
585        assert_eq!(segments, vec![(10, 26)]);
586    }
587
588    #[test]
589    fn test_iter_offset() {
590        let mut assr = Assembler::new();
591        assert_eq!(assr.add(0, 16), Ok(()));
592        let segments: Vec<_> = assr.iter_data(100).collect();
593        assert_eq!(segments, vec![(100, 116)]);
594    }
595
596    #[test]
597    fn test_iter_one_front() {
598        let mut assr = Assembler::new();
599        assert_eq!(assr.add(0, 4), Ok(()));
600        let segments: Vec<_> = assr.iter_data(10).collect();
601        assert_eq!(segments, vec![(10, 14)]);
602    }
603
604    #[test]
605    fn test_iter_one_back() {
606        let mut assr = Assembler::new();
607        assert_eq!(assr.add(12, 4), Ok(()));
608        let segments: Vec<_> = assr.iter_data(10).collect();
609        assert_eq!(segments, vec![(22, 26)]);
610    }
611
612    #[test]
613    fn test_iter_one_mid() {
614        let mut assr = Assembler::new();
615        assert_eq!(assr.add(4, 8), Ok(()));
616        let segments: Vec<_> = assr.iter_data(10).collect();
617        assert_eq!(segments, vec![(14, 22)]);
618    }
619
620    #[test]
621    fn test_iter_one_trailing_gap() {
622        let assr = contigs![(4, 8)];
623        let segments: Vec<_> = assr.iter_data(100).collect();
624        assert_eq!(segments, vec![(104, 112)]);
625    }
626
627    #[test]
628    fn test_iter_two_split() {
629        let assr = contigs![(2, 6), (4, 1)];
630        let segments: Vec<_> = assr.iter_data(100).collect();
631        assert_eq!(segments, vec![(102, 108), (112, 113)]);
632    }
633
634    #[test]
635    fn test_iter_three_split() {
636        let assr = contigs![(2, 6), (2, 1), (2, 2)];
637        let segments: Vec<_> = assr.iter_data(100).collect();
638        assert_eq!(segments, vec![(102, 108), (110, 111), (113, 115)]);
639    }
640
641    #[test]
642    fn test_issue_694() {
643        let mut assr = Assembler::new();
644        assert_eq!(assr.add(0, 1), Ok(()));
645        assert_eq!(assr.add(2, 1), Ok(()));
646        assert_eq!(assr.add(1, 1), Ok(()));
647    }
648
649    #[test]
650    fn test_add_then_remove_front() {
651        let mut assr = Assembler::new();
652        assert_eq!(assr.add(50, 10), Ok(()));
653        assert_eq!(assr.add_then_remove_front(10, 10), Ok(0));
654        assert_eq!(assr, contigs![(10, 10), (30, 10)]);
655    }
656
657    #[test]
658    fn test_add_then_remove_front_at_front() {
659        let mut assr = Assembler::new();
660        assert_eq!(assr.add(50, 10), Ok(()));
661        assert_eq!(assr.add_then_remove_front(0, 10), Ok(10));
662        assert_eq!(assr, contigs![(40, 10)]);
663    }
664
665    #[test]
666    fn test_add_then_remove_front_at_front_touch() {
667        let mut assr = Assembler::new();
668        assert_eq!(assr.add(50, 10), Ok(()));
669        assert_eq!(assr.add_then_remove_front(0, 50), Ok(60));
670        assert_eq!(assr, contigs![]);
671    }
672
673    #[test]
674    fn test_add_then_remove_front_at_front_full() {
675        let mut assr = Assembler::new();
676        for c in 1..=ASSEMBLER_MAX_SEGMENT_COUNT {
677            assert_eq!(assr.add(c * 10, 3), Ok(()));
678        }
679        // Maximum of allowed holes is reached
680        let assr_before = assr.clone();
681        assert_eq!(assr.add_then_remove_front(1, 3), Err(TooManyHolesError));
682        assert_eq!(assr_before, assr);
683    }
684
685    #[test]
686    fn test_add_then_remove_front_at_front_full_offset_0() {
687        let mut assr = Assembler::new();
688        for c in 1..=ASSEMBLER_MAX_SEGMENT_COUNT {
689            assert_eq!(assr.add(c * 10, 3), Ok(()));
690        }
691        assert_eq!(assr.add_then_remove_front(0, 3), Ok(3));
692    }
693
694    // Test against an obviously-correct but inefficient bitmap impl.
695    #[test]
696    fn test_random() {
697        use rand::Rng;
698
699        const MAX_INDEX: usize = 256;
700
701        for max_size in [2, 5, 10, 100] {
702            for _ in 0..300 {
703                //println!("===");
704                let mut assr = Assembler::new();
705                let mut map = [false; MAX_INDEX];
706
707                for _ in 0..60 {
708                    let offset = rand::thread_rng().gen_range(0..MAX_INDEX - max_size - 1);
709                    let size = rand::thread_rng().gen_range(1..=max_size);
710
711                    //println!("add {}..{} {}", offset, offset + size, size);
712                    // Real impl
713                    let res = assr.add(offset, size);
714
715                    // Bitmap impl
716                    let mut map2 = map;
717                    map2[offset..][..size].fill(true);
718
719                    let mut contigs = vec![];
720                    let mut hole: usize = 0;
721                    let mut data: usize = 0;
722                    for b in map2 {
723                        if b {
724                            data += 1;
725                        } else {
726                            if data != 0 {
727                                contigs.push((hole, data));
728                                hole = 0;
729                                data = 0;
730                            }
731                            hole += 1;
732                        }
733                    }
734
735                    // Compare.
736                    let wanted_res = if contigs.len() > ASSEMBLER_MAX_SEGMENT_COUNT {
737                        Err(TooManyHolesError)
738                    } else {
739                        Ok(())
740                    };
741                    assert_eq!(res, wanted_res);
742                    if res.is_ok() {
743                        map = map2;
744                        assert_eq!(assr, Assembler::from(contigs));
745                    }
746                }
747            }
748        }
749    }
750}