1use std::fmt;
2use std::iter::FusedIterator;
3
4pub type Slot = Option<usize>;
8
9#[doc(hidden)]
14#[derive(Clone, Debug)]
15pub struct Locations(Vec<Slot>);
16
17impl Locations {
18 pub fn pos(&self, i: usize) -> Option<(usize, usize)> {
23 let (s, e) = (i * 2, i * 2 + 1);
24 match (self.0.get(s), self.0.get(e)) {
25 (Some(&Some(s)), Some(&Some(e))) => Some((s, e)),
26 _ => None,
27 }
28 }
29
30 pub fn iter(&self) -> SubCapturesPosIter<'_> {
34 SubCapturesPosIter { idx: 0, locs: self }
35 }
36
37 pub fn len(&self) -> usize {
42 self.0.len() / 2
43 }
44
45 pub(crate) fn as_slots(&mut self) -> &mut [Slot] {
47 &mut self.0
48 }
49}
50
51#[derive(Clone, Debug)]
58pub struct SubCapturesPosIter<'c> {
59 idx: usize,
60 locs: &'c Locations,
61}
62
63impl<'c> Iterator for SubCapturesPosIter<'c> {
64 type Item = Option<(usize, usize)>;
65
66 fn next(&mut self) -> Option<Option<(usize, usize)>> {
67 if self.idx >= self.locs.len() {
68 return None;
69 }
70 let x = match self.locs.pos(self.idx) {
71 None => Some(None),
72 Some((s, e)) => Some(Some((s, e))),
73 };
74 self.idx += 1;
75 x
76 }
77
78 fn size_hint(&self) -> (usize, Option<usize>) {
79 let len = self.locs.len() - self.idx;
80 (len, Some(len))
81 }
82
83 fn count(self) -> usize {
84 self.len()
85 }
86}
87
88impl<'c> ExactSizeIterator for SubCapturesPosIter<'c> {}
89
90impl<'c> FusedIterator for SubCapturesPosIter<'c> {}
91
92pub trait RegularExpression: Sized + fmt::Debug {
105 type Text: ?Sized + fmt::Debug;
107
108 fn slots_len(&self) -> usize;
111
112 fn locations(&self) -> Locations {
114 Locations(vec![None; self.slots_len()])
115 }
116
117 fn next_after_empty(&self, text: &Self::Text, i: usize) -> usize;
123
124 fn shortest_match_at(
126 &self,
127 text: &Self::Text,
128 start: usize,
129 ) -> Option<usize>;
130
131 fn is_match_at(&self, text: &Self::Text, start: usize) -> bool;
133
134 fn find_at(
136 &self,
137 text: &Self::Text,
138 start: usize,
139 ) -> Option<(usize, usize)>;
140
141 fn captures_read_at(
144 &self,
145 locs: &mut Locations,
146 text: &Self::Text,
147 start: usize,
148 ) -> Option<(usize, usize)>;
149
150 fn find_iter(self, text: &Self::Text) -> Matches<'_, Self> {
153 Matches { re: self, text, last_end: 0, last_match: None }
154 }
155
156 fn captures_iter(self, text: &Self::Text) -> CaptureMatches<'_, Self> {
159 CaptureMatches(self.find_iter(text))
160 }
161}
162
163#[derive(Debug)]
165pub struct Matches<'t, R>
166where
167 R: RegularExpression,
168 R::Text: 't,
169{
170 re: R,
171 text: &'t R::Text,
172 last_end: usize,
173 last_match: Option<usize>,
174}
175
176impl<'t, R> Matches<'t, R>
177where
178 R: RegularExpression,
179 R::Text: 't,
180{
181 pub fn text(&self) -> &'t R::Text {
183 self.text
184 }
185
186 pub fn regex(&self) -> &R {
188 &self.re
189 }
190}
191
192impl<'t, R> Iterator for Matches<'t, R>
193where
194 R: RegularExpression,
195 R::Text: 't + AsRef<[u8]>,
196{
197 type Item = (usize, usize);
198
199 fn next(&mut self) -> Option<(usize, usize)> {
200 if self.last_end > self.text.as_ref().len() {
201 return None;
202 }
203 let (s, e) = match self.re.find_at(self.text, self.last_end) {
204 None => return None,
205 Some((s, e)) => (s, e),
206 };
207 if s == e {
208 self.last_end = self.re.next_after_empty(self.text, e);
212 if Some(e) == self.last_match {
215 return self.next();
216 }
217 } else {
218 self.last_end = e;
219 }
220 self.last_match = Some(e);
221 Some((s, e))
222 }
223}
224
225impl<'t, R> FusedIterator for Matches<'t, R>
226where
227 R: RegularExpression,
228 R::Text: 't + AsRef<[u8]>,
229{
230}
231
232#[derive(Debug)]
235pub struct CaptureMatches<'t, R>(Matches<'t, R>)
236where
237 R: RegularExpression,
238 R::Text: 't;
239
240impl<'t, R> CaptureMatches<'t, R>
241where
242 R: RegularExpression,
243 R::Text: 't,
244{
245 pub fn text(&self) -> &'t R::Text {
247 self.0.text()
248 }
249
250 pub fn regex(&self) -> &R {
252 self.0.regex()
253 }
254}
255
256impl<'t, R> Iterator for CaptureMatches<'t, R>
257where
258 R: RegularExpression,
259 R::Text: 't + AsRef<[u8]>,
260{
261 type Item = Locations;
262
263 fn next(&mut self) -> Option<Locations> {
264 if self.0.last_end > self.0.text.as_ref().len() {
265 return None;
266 }
267 let mut locs = self.0.re.locations();
268 let (s, e) = match self.0.re.captures_read_at(
269 &mut locs,
270 self.0.text,
271 self.0.last_end,
272 ) {
273 None => return None,
274 Some((s, e)) => (s, e),
275 };
276 if s == e {
277 self.0.last_end = self.0.re.next_after_empty(self.0.text, e);
278 if Some(e) == self.0.last_match {
279 return self.next();
280 }
281 } else {
282 self.0.last_end = e;
283 }
284 self.0.last_match = Some(e);
285 Some(locs)
286 }
287}
288
289impl<'t, R> FusedIterator for CaptureMatches<'t, R>
290where
291 R: RegularExpression,
292 R::Text: 't + AsRef<[u8]>,
293{
294}