Skip to main content

hir_ty/diagnostics/match_check/
pat_util.rs

1//! Pattern utilities.
2//!
3//! Originates from `rustc_hir::pat_util`
4
5use std::iter::Enumerate;
6
7pub(crate) struct EnumerateAndAdjust<I> {
8    enumerate: Enumerate<I>,
9    gap_pos: usize,
10    gap_len: usize,
11}
12
13impl<I> Iterator for EnumerateAndAdjust<I>
14where
15    I: Iterator,
16{
17    type Item = (usize, <I as Iterator>::Item);
18
19    fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
20        self.enumerate
21            .next()
22            .map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem))
23    }
24
25    fn size_hint(&self) -> (usize, Option<usize>) {
26        self.enumerate.size_hint()
27    }
28}
29
30pub(crate) trait EnumerateAndAdjustIterator {
31    fn enumerate_and_adjust(
32        self,
33        expected_len: usize,
34        gap_pos: Option<usize>,
35    ) -> EnumerateAndAdjust<Self>
36    where
37        Self: Sized;
38}
39
40impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
41    /// When there is a list of items with a gap of an unknown length inside, and another list
42    /// of item it should be zipped against, this operates on the list with the gap and returns,
43    /// for each item, the index it should match in the other list.
44    ///
45    /// When compiling Rust, such situation often occurs for tuple structs/tuples with a rest pattern
46    /// that should be matched against the fields.
47    fn enumerate_and_adjust(
48        self,
49        expected_len: usize,
50        gap_pos: Option<usize>,
51    ) -> EnumerateAndAdjust<Self>
52    where
53        Self: Sized,
54    {
55        let actual_len = self.len();
56        EnumerateAndAdjust {
57            enumerate: self.enumerate(),
58            gap_pos: gap_pos.unwrap_or(expected_len),
59            gap_len: expected_len - actual_len,
60        }
61    }
62}