ms_codeview/utils/
iter.rs

1use std::ops::Range;
2
3/// Allows iterators to report the remaining, unparsed bytes within an iterator.
4///
5/// This is for iterators that parse items from `&[u8]` buffers or similar.
6pub trait HasRestLen {
7    /// Returns the number of bytes (or elements, abstractly) that have not yet been parsed by this
8    /// iterator.
9    fn rest_len(&self) -> usize;
10}
11
12/// An iterator adapter which reports the byte ranges of the items that are iterated by the
13/// underlying iterator. The underlying iterator must implement `HasRestLen`.
14pub struct IterWithRange<I> {
15    original_len: usize,
16    inner: I,
17}
18
19impl<I> IterWithRange<I> {
20    /// The number of items (usually bytes) that were present in the inner iterator when this
21    /// `IterWithRange` was created. This value allows us to convert the "bytes remaining" value
22    /// (`rest_len()`, which is what the inner iterator operates directly on) to an offset from the
23    /// beginning of a buffer.
24    pub fn original_len(&self) -> usize {
25        self.original_len
26    }
27
28    /// Gets access to the inner iterator.
29    pub fn inner(&self) -> &I {
30        &self.inner
31    }
32
33    /// Gets mutable access to the inner iterator.
34    ///
35    /// Be warned!  If you modify this iterator, make sure you don't break its relationship with
36    /// the `original_len` value.  Iterating items from it is fine, because that should never
37    /// break the relationship with `original_len`.
38    ///
39    /// What would break it would be replacing the inner iterator with one that has a length that
40    /// is greater than `original_len`.
41    pub fn inner_mut(&mut self) -> &mut I {
42        &mut self.inner
43    }
44
45    /// The current position in the iteration range.
46    #[inline(always)]
47    pub fn pos(&self) -> usize
48    where
49        I: HasRestLen,
50    {
51        self.original_len - self.inner.rest_len()
52    }
53}
54
55impl<I: Iterator> Iterator for IterWithRange<I>
56where
57    I: HasRestLen,
58{
59    type Item = (Range<usize>, I::Item);
60
61    fn next(&mut self) -> Option<Self::Item> {
62        let pos_before = self.pos();
63        let item = self.inner.next()?;
64        let pos_after = self.pos();
65        Some((pos_before..pos_after, item))
66    }
67}
68
69/// An extension trait for iterators that converts an `Iterator` into an `IterWithRange`.
70/// Use `foo.with_ranges()` to convert (augment) the iterator.
71pub trait IteratorWithRangesExt: Sized {
72    /// Augments this iterator with information about the byte range of each underlying item.
73    fn with_ranges(self) -> IterWithRange<Self>;
74}
75
76impl<I> IteratorWithRangesExt for I
77where
78    I: Iterator + HasRestLen,
79{
80    fn with_ranges(self) -> IterWithRange<Self> {
81        IterWithRange {
82            original_len: self.rest_len(),
83            inner: self,
84        }
85    }
86}