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}