Skip to main content

ct_regex_internal/expr/
iter.rs

1use std::iter::FusedIterator;
2use std::marker::PhantomData;
3use std::ops::Range;
4
5use crate::anchor::Anchor;
6use crate::expr::{IndexedCaptures, FromRanges, Regex};
7use crate::haystack::{HaystackItem, HaystackOf};
8use crate::matcher::Matcher;
9
10/// An `Iterator` over each match in the haystack, as a [`Range<usize>`](Range). See
11/// [`Regex::range_of_all_matches`].
12#[derive(#[automatically_derived]
impl<'a, R: ::core::fmt::Debug, I: ::core::fmt::Debug, H: ::core::fmt::Debug,
    const N : usize> ::core::fmt::Debug for RangeOfAllMatches<'a, R, I, H, N>
    where R: Regex<I, N> + ?Sized, I: HaystackItem, H: HaystackOf<'a, I> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f,
            "RangeOfAllMatches", "hay", &self.hay, "overlapping",
            &self.overlapping, "last_check", &self.last_check, "_phantom",
            &&self._phantom)
    }
}Debug, #[automatically_derived]
impl<'a, R: ::core::clone::Clone, I: ::core::clone::Clone,
    H: ::core::clone::Clone, const N : usize> ::core::clone::Clone for
    RangeOfAllMatches<'a, R, I, H, N> where R: Regex<I, N> + ?Sized,
    I: HaystackItem, H: HaystackOf<'a, I> {
    #[inline]
    fn clone(&self) -> RangeOfAllMatches<'a, R, I, H, N> {
        RangeOfAllMatches {
            hay: ::core::clone::Clone::clone(&self.hay),
            overlapping: ::core::clone::Clone::clone(&self.overlapping),
            last_check: ::core::clone::Clone::clone(&self.last_check),
            _phantom: ::core::clone::Clone::clone(&self._phantom),
        }
    }
}Clone, #[automatically_derived]
impl<'a, R: ::core::hash::Hash, I: ::core::hash::Hash, H: ::core::hash::Hash,
    const N : usize> ::core::hash::Hash for RangeOfAllMatches<'a, R, I, H, N>
    where R: Regex<I, N> + ?Sized, I: HaystackItem, H: HaystackOf<'a, I> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.hay, state);
        ::core::hash::Hash::hash(&self.overlapping, state);
        ::core::hash::Hash::hash(&self.last_check, state);
        ::core::hash::Hash::hash(&self._phantom, state)
    }
}Hash)]
13pub struct RangeOfAllMatches<'a, R, I, H, const N: usize>
14where
15    R: Regex<I, N> + ?Sized,
16    I: HaystackItem,
17    H: HaystackOf<'a, I>,
18{
19    pub(crate) hay: H,
20    pub(crate) overlapping: bool,
21    pub(crate) last_check: bool,
22    pub(crate) _phantom: PhantomData<(&'a (), I, R)>,
23}
24
25impl<'a, R, I, H, const N: usize> RangeOfAllMatches<'a, R, I, H, N>
26where
27    R: Regex<I, N> + ?Sized,
28    I: HaystackItem,
29    H: HaystackOf<'a, I>,
30{
31    pub fn new(hay: H, overlapping: bool) -> Self {
32        RangeOfAllMatches {
33            hay,
34            overlapping,
35            last_check: false,
36            _phantom: PhantomData,
37        }
38    }
39}
40
41impl<'a, R, I, H, const N: usize> Iterator for RangeOfAllMatches<'a, R, I, H, N>
42where
43    R: Regex<I, N> + ?Sized,
44    I: HaystackItem,
45    H: HaystackOf<'a, I>,
46{
47    type Item = Range<usize>;
48
49    fn next(&mut self) -> Option<Self::Item> {
50        if self.last_check {
51            return None;
52        }
53
54        self.last_check = self.hay.item().is_none();
55        let mut ret = None;
56
57        if R::Anchors::assert(&self.hay).continue_value()? {
58            let start = self.hay.index();
59
60            if let Some(state_fork) = R::Pattern::all_matches(&mut self.hay).next() {
61                ret = Some(start..state_fork);
62
63                // If start == state_fork, we have a zero-width pattern and have already matched
64                // this index. We need to progress normally.
65
66                if !self.overlapping && start != state_fork {
67                    self.hay.rollback(state_fork);
68                    return ret.or_else(|| self.next());
69                }
70            }
71
72            self.hay.rollback(start);
73        }
74
75        self.hay.progress();
76        ret.or_else(|| self.next())
77    }
78}
79
80impl<'a, R, I, H, const N: usize> FusedIterator for RangeOfAllMatches<'a, R, I, H, N>
81where
82    R: Regex<I, N> + ?Sized,
83    I: HaystackItem,
84    H: HaystackOf<'a, I>,
85{}
86
87/// An `Iterator` over each match in the haystack, as an `H::Slice`. See
88/// [`Regex::slice_all_matches`].
89#[derive(#[automatically_derived]
impl<'a, R: ::core::fmt::Debug, I: ::core::fmt::Debug, H: ::core::fmt::Debug,
    const N : usize> ::core::fmt::Debug for SliceAllMatches<'a, R, I, H, N>
    where R: Regex<I, N> + ?Sized, I: HaystackItem, H: HaystackOf<'a, I> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "SliceAllMatches", "inner", &&self.inner)
    }
}Debug, #[automatically_derived]
impl<'a, R: ::core::clone::Clone, I: ::core::clone::Clone,
    H: ::core::clone::Clone, const N : usize> ::core::clone::Clone for
    SliceAllMatches<'a, R, I, H, N> where R: Regex<I, N> + ?Sized,
    I: HaystackItem, H: HaystackOf<'a, I> {
    #[inline]
    fn clone(&self) -> SliceAllMatches<'a, R, I, H, N> {
        SliceAllMatches { inner: ::core::clone::Clone::clone(&self.inner) }
    }
}Clone, #[automatically_derived]
impl<'a, R: ::core::hash::Hash, I: ::core::hash::Hash, H: ::core::hash::Hash,
    const N : usize> ::core::hash::Hash for SliceAllMatches<'a, R, I, H, N>
    where R: Regex<I, N> + ?Sized, I: HaystackItem, H: HaystackOf<'a, I> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.inner, state)
    }
}Hash)]
90pub struct SliceAllMatches<'a, R, I, H, const N: usize>
91where
92    R: Regex<I, N> + ?Sized,
93    I: HaystackItem,
94    H: HaystackOf<'a, I>,
95{
96    pub(crate) inner: RangeOfAllMatches<'a, R, I, H, N>,
97}
98
99impl<'a, R, I, H, const N: usize> Iterator for SliceAllMatches<'a, R, I, H, N>
100where
101    R: Regex<I, N> + ?Sized,
102    I: HaystackItem,
103    H: HaystackOf<'a, I>,
104{
105    type Item = H::Slice;
106
107    fn next(&mut self) -> Option<Self::Item> {
108        let range = self.inner.next()?;
109        Some(self.inner.hay.slice_with(range))
110    }
111}
112
113impl<'a, R, I, H, const N: usize> FusedIterator for SliceAllMatches<'a, R, I, H, N>
114where
115    R: Regex<I, N> + ?Sized,
116    I: HaystackItem,
117    H: HaystackOf<'a, I>,
118{}
119
120/// An `Iterator` over each capture in the haystack, as an `R::Capture`. See
121/// [`Regex::find_all_captures`].
122#[derive(#[automatically_derived]
impl<'a, R: ::core::fmt::Debug, I: ::core::fmt::Debug, H: ::core::fmt::Debug,
    const N : usize> ::core::fmt::Debug for FindAllCaptures<'a, R, I, H, N>
    where R: Regex<I, N> + ?Sized, I: HaystackItem, H: HaystackOf<'a, I> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f,
            "FindAllCaptures", "hay", &self.hay, "overlapping",
            &self.overlapping, "last_check", &self.last_check, "_phantom",
            &&self._phantom)
    }
}Debug, #[automatically_derived]
impl<'a, R: ::core::clone::Clone, I: ::core::clone::Clone,
    H: ::core::clone::Clone, const N : usize> ::core::clone::Clone for
    FindAllCaptures<'a, R, I, H, N> where R: Regex<I, N> + ?Sized,
    I: HaystackItem, H: HaystackOf<'a, I> {
    #[inline]
    fn clone(&self) -> FindAllCaptures<'a, R, I, H, N> {
        FindAllCaptures {
            hay: ::core::clone::Clone::clone(&self.hay),
            overlapping: ::core::clone::Clone::clone(&self.overlapping),
            last_check: ::core::clone::Clone::clone(&self.last_check),
            _phantom: ::core::clone::Clone::clone(&self._phantom),
        }
    }
}Clone, #[automatically_derived]
impl<'a, R: ::core::hash::Hash, I: ::core::hash::Hash, H: ::core::hash::Hash,
    const N : usize> ::core::hash::Hash for FindAllCaptures<'a, R, I, H, N>
    where R: Regex<I, N> + ?Sized, I: HaystackItem, H: HaystackOf<'a, I> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.hay, state);
        ::core::hash::Hash::hash(&self.overlapping, state);
        ::core::hash::Hash::hash(&self.last_check, state);
        ::core::hash::Hash::hash(&self._phantom, state)
    }
}Hash)]
123pub struct FindAllCaptures<'a, R, I, H, const N: usize>
124where
125    R: Regex<I, N> + ?Sized,
126    I: HaystackItem,
127    H: HaystackOf<'a, I>,
128{
129    pub(crate) hay: H,
130    pub(crate) overlapping: bool,
131    pub(crate) last_check: bool,
132    pub(crate) _phantom: PhantomData<(&'a (), I, R)>,
133}
134
135impl<'a, R, I, H, const N: usize> FindAllCaptures<'a, R, I, H, N>
136where
137    R: Regex<I, N> + ?Sized,
138    I: HaystackItem,
139    H: HaystackOf<'a, I>,
140{
141    pub fn new(hay: H, overlapping: bool) -> Self {
142        Self {
143            hay,
144            overlapping,
145            last_check: false,
146            _phantom: PhantomData,
147        }
148    }
149}
150
151impl<'a, R, I, H, const N: usize> Iterator for FindAllCaptures<'a, R, I, H, N>
152where
153    R: Regex<I, N> + ?Sized,
154    I: HaystackItem + 'a,
155    H: HaystackOf<'a, I>,
156{
157    type Item = R::Capture<'a, H::Slice>;
158
159    fn next(&mut self) -> Option<Self::Item> {
160        if self.last_check {
161            return None;
162        }
163
164        self.last_check = self.hay.item().is_none();
165        let mut ret = None;
166
167        if R::Anchors::assert(&self.hay).continue_value()? {
168            let start = self.hay.index();
169            let mut caps = IndexedCaptures::default();
170
171            if let Some((
172                state_fork,
173                mut caps_fork
174            )) = R::Pattern::all_captures(&mut self.hay, &mut caps).next() {
175                caps_fork.push(0, start..state_fork);
176                ret = Some(
177                    R::Capture::from_ranges(caps_fork.into_array(), self.hay.inner_slice())
178                        .expect("failed to convert captures despite matching correctly")
179                );
180
181                // If start == state_fork, we have a zero-width pattern and have already matched
182                // this index. We need to progress normally.
183
184                if !self.overlapping && start != state_fork {
185                    self.hay.rollback(state_fork);
186                    return ret.or_else(|| self.next());
187                }
188            }
189
190            self.hay.rollback(start);
191        }
192
193        self.hay.progress();
194        ret.or_else(|| self.next())
195    }
196}
197
198impl<'a, R, I, H, const N: usize> FusedIterator for FindAllCaptures<'a, R, I, H, N>
199where
200    R: Regex<I, N> + ?Sized,
201    I: HaystackItem + 'a,
202    H: HaystackOf<'a, I>,
203{}