ms_pdb/utils/
iter.rs

1//! Iterator utilities
2
3use std::ops::Range;
4
5/// Allows iterators to report the remaining, unparsed bytes within an iterator.
6///
7/// This is for iterators that parse items from `&[u8]` buffers or similar.
8pub trait HasRestLen {
9    /// Returns the number of bytes (or elements, abstractly) that have not yet been parsed by this
10    /// iterator.
11    fn rest_len(&self) -> usize;
12}
13
14/// An iterator adapter which reports the byte ranges of the items that are iterated by the
15/// underlying iterator. The underlying iterator must implement `HasRestLen`.
16pub struct IterWithRange<I> {
17    original_len: usize,
18    inner: I,
19}
20
21impl<I> IterWithRange<I> {
22    /// The number of items (usually bytes) that were present in the inner iterator when this
23    /// `IterWithRange` was created. This value allows us to convert the "bytes remaining" value
24    /// (`rest_len()`, which is what the inner iterator operates directly on) to an offset from the
25    /// beginning of a buffer.
26    pub fn original_len(&self) -> usize {
27        self.original_len
28    }
29
30    /// Gets access to the inner iterator.
31    pub fn inner(&self) -> &I {
32        &self.inner
33    }
34
35    /// Gets mutable access to the inner iterator.
36    ///
37    /// Be warned!  If you modify this iterator, make sure you don't break its relationship with
38    /// the `original_len` value.  Iterating items from it is fine, because that should never
39    /// break the relationship with `original_len`.
40    ///
41    /// What would break it would be replacing the inner iterator with one that has a length that
42    /// is greater than `original_len`.
43    pub fn inner_mut(&mut self) -> &mut I {
44        &mut self.inner
45    }
46
47    /// The current position in the iteration range.
48    #[inline(always)]
49    pub fn pos(&self) -> usize
50    where
51        I: HasRestLen,
52    {
53        self.original_len - self.inner.rest_len()
54    }
55}
56
57impl<I: Iterator> Iterator for IterWithRange<I>
58where
59    I: HasRestLen,
60{
61    type Item = (Range<usize>, I::Item);
62
63    fn next(&mut self) -> Option<Self::Item> {
64        let pos_before = self.pos();
65        let item = self.inner.next()?;
66        let pos_after = self.pos();
67        Some((pos_before..pos_after, item))
68    }
69}
70
71/// An extension trait for iterators that converts an `Iterator` into an `IterWithRange`.
72/// Use `foo.with_ranges()` to convert (augment) the iterator.
73pub trait IteratorWithRangesExt: Sized {
74    /// Augments this iterator with information about the byte range of each underlying item.
75    fn with_ranges(self) -> IterWithRange<Self>;
76}
77
78impl<I> IteratorWithRangesExt for I
79where
80    I: Iterator + HasRestLen,
81{
82    fn with_ranges(self) -> IterWithRange<Self> {
83        IterWithRange {
84            original_len: self.rest_len(),
85            inner: self,
86        }
87    }
88}
89
90use std::collections::BTreeMap;
91
92/// Reads a slice of items and groups them using a function over the items.
93pub fn group_by<'a, T, F, K>(s: &'a [T], f: F) -> BTreeMap<K, Vec<&'a T>>
94where
95    F: Fn(&T) -> K,
96    K: Ord + Eq,
97{
98    let mut out: BTreeMap<K, Vec<&'a T>> = BTreeMap::new();
99
100    for item in s.iter() {
101        let key = f(item);
102        if let Some(list) = out.get_mut(&key) {
103            list.push(item);
104        } else {
105            out.insert(key, vec![item]);
106        }
107    }
108
109    out
110}
111
112/// Reads a sequence of items and groups them using a function over the items.
113pub fn group_by_iter_ref<'a, T, F, I, K>(iter: I, f: F) -> BTreeMap<K, Vec<&'a T>>
114where
115    I: Iterator<Item = &'a T>,
116    F: Fn(&T) -> K,
117    K: Ord + Eq,
118{
119    let mut out: BTreeMap<K, Vec<&'a T>> = BTreeMap::new();
120
121    for item in iter {
122        let key = f(item);
123        if let Some(list) = out.get_mut(&key) {
124            list.push(item);
125        } else {
126            out.insert(key, vec![item]);
127        }
128    }
129
130    out
131}
132
133/// Reads a sequence of items and groups them using a function over the items.
134pub fn group_by_iter<I, F, K>(iter: I, f: F) -> BTreeMap<K, Vec<I::Item>>
135where
136    I: Iterator,
137    F: Fn(&I::Item) -> K,
138    K: Ord + Eq,
139{
140    let mut out: BTreeMap<K, Vec<I::Item>> = BTreeMap::new();
141
142    for item in iter {
143        let key = f(&item);
144        if let Some(list) = out.get_mut(&key) {
145            list.push(item);
146        } else {
147            out.insert(key, vec![item]);
148        }
149    }
150
151    out
152}