Skip to main content

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