xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/regex-1.10.4/src/regexset/string.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 use alloc::string::String;
2 
3 use regex_automata::{meta, Input, PatternID, PatternSet, PatternSetIter};
4 
5 use crate::{Error, RegexSetBuilder};
6 
7 /// Match multiple, possibly overlapping, regexes in a single search.
8 ///
9 /// A regex set corresponds to the union of zero or more regular expressions.
10 /// That is, a regex set will match a haystack when at least one of its
11 /// constituent regexes matches. A regex set as its formulated here provides a
12 /// touch more power: it will also report *which* regular expressions in the
13 /// set match. Indeed, this is the key difference between regex sets and a
14 /// single `Regex` with many alternates, since only one alternate can match at
15 /// a time.
16 ///
17 /// For example, consider regular expressions to match email addresses and
18 /// domains: `[a-z]+@[a-z]+\.(com|org|net)` and `[a-z]+\.(com|org|net)`. If a
19 /// regex set is constructed from those regexes, then searching the haystack
20 /// `[email protected]` will report both regexes as matching. Of course, one
21 /// could accomplish this by compiling each regex on its own and doing two
22 /// searches over the haystack. The key advantage of using a regex set is
23 /// that it will report the matching regexes using a *single pass through the
24 /// haystack*. If one has hundreds or thousands of regexes to match repeatedly
25 /// (like a URL router for a complex web application or a user agent matcher),
26 /// then a regex set *can* realize huge performance gains.
27 ///
28 /// # Limitations
29 ///
30 /// Regex sets are limited to answering the following two questions:
31 ///
32 /// 1. Does any regex in the set match?
33 /// 2. If so, which regexes in the set match?
34 ///
35 /// As with the main [`Regex`][crate::Regex] type, it is cheaper to ask (1)
36 /// instead of (2) since the matching engines can stop after the first match
37 /// is found.
38 ///
39 /// You cannot directly extract [`Match`][crate::Match] or
40 /// [`Captures`][crate::Captures] objects from a regex set. If you need these
41 /// operations, the recommended approach is to compile each pattern in the set
42 /// independently and scan the exact same haystack a second time with those
43 /// independently compiled patterns:
44 ///
45 /// ```
46 /// use regex::{Regex, RegexSet};
47 ///
48 /// let patterns = ["foo", "bar"];
49 /// // Both patterns will match different ranges of this string.
50 /// let hay = "barfoo";
51 ///
52 /// // Compile a set matching any of our patterns.
53 /// let set = RegexSet::new(patterns).unwrap();
54 /// // Compile each pattern independently.
55 /// let regexes: Vec<_> = set
56 ///     .patterns()
57 ///     .iter()
58 ///     .map(|pat| Regex::new(pat).unwrap())
59 ///     .collect();
60 ///
61 /// // Match against the whole set first and identify the individual
62 /// // matching patterns.
63 /// let matches: Vec<&str> = set
64 ///     .matches(hay)
65 ///     .into_iter()
66 ///     // Dereference the match index to get the corresponding
67 ///     // compiled pattern.
68 ///     .map(|index| &regexes[index])
69 ///     // To get match locations or any other info, we then have to search the
70 ///     // exact same haystack again, using our separately-compiled pattern.
71 ///     .map(|re| re.find(hay).unwrap().as_str())
72 ///     .collect();
73 ///
74 /// // Matches arrive in the order the constituent patterns were declared,
75 /// // not the order they appear in the haystack.
76 /// assert_eq!(vec!["foo", "bar"], matches);
77 /// ```
78 ///
79 /// # Performance
80 ///
81 /// A `RegexSet` has the same performance characteristics as `Regex`. Namely,
82 /// search takes `O(m * n)` time, where `m` is proportional to the size of the
83 /// regex set and `n` is proportional to the length of the haystack.
84 ///
85 /// # Trait implementations
86 ///
87 /// The `Default` trait is implemented for `RegexSet`. The default value
88 /// is an empty set. An empty set can also be explicitly constructed via
89 /// [`RegexSet::empty`].
90 ///
91 /// # Example
92 ///
93 /// This shows how the above two regexes (for matching email addresses and
94 /// domains) might work:
95 ///
96 /// ```
97 /// use regex::RegexSet;
98 ///
99 /// let set = RegexSet::new(&[
100 ///     r"[a-z]+@[a-z]+\.(com|org|net)",
101 ///     r"[a-z]+\.(com|org|net)",
102 /// ]).unwrap();
103 ///
104 /// // Ask whether any regexes in the set match.
105 /// assert!(set.is_match("[email protected]"));
106 ///
107 /// // Identify which regexes in the set match.
108 /// let matches: Vec<_> = set.matches("[email protected]").into_iter().collect();
109 /// assert_eq!(vec![0, 1], matches);
110 ///
111 /// // Try again, but with a haystack that only matches one of the regexes.
112 /// let matches: Vec<_> = set.matches("example.com").into_iter().collect();
113 /// assert_eq!(vec![1], matches);
114 ///
115 /// // Try again, but with a haystack that doesn't match any regex in the set.
116 /// let matches: Vec<_> = set.matches("example").into_iter().collect();
117 /// assert!(matches.is_empty());
118 /// ```
119 ///
120 /// Note that it would be possible to adapt the above example to using `Regex`
121 /// with an expression like:
122 ///
123 /// ```text
124 /// (?P<email>[a-z]+@(?P<email_domain>[a-z]+[.](com|org|net)))|(?P<domain>[a-z]+[.](com|org|net))
125 /// ```
126 ///
127 /// After a match, one could then inspect the capture groups to figure out
128 /// which alternates matched. The problem is that it is hard to make this
129 /// approach scale when there are many regexes since the overlap between each
130 /// alternate isn't always obvious to reason about.
131 #[derive(Clone)]
132 pub struct RegexSet {
133     pub(crate) meta: meta::Regex,
134     pub(crate) patterns: alloc::sync::Arc<[String]>,
135 }
136 
137 impl RegexSet {
138     /// Create a new regex set with the given regular expressions.
139     ///
140     /// This takes an iterator of `S`, where `S` is something that can produce
141     /// a `&str`. If any of the strings in the iterator are not valid regular
142     /// expressions, then an error is returned.
143     ///
144     /// # Example
145     ///
146     /// Create a new regex set from an iterator of strings:
147     ///
148     /// ```
149     /// use regex::RegexSet;
150     ///
151     /// let set = RegexSet::new([r"\w+", r"\d+"]).unwrap();
152     /// assert!(set.is_match("foo"));
153     /// ```
new<I, S>(exprs: I) -> Result<RegexSet, Error> where S: AsRef<str>, I: IntoIterator<Item = S>,154     pub fn new<I, S>(exprs: I) -> Result<RegexSet, Error>
155     where
156         S: AsRef<str>,
157         I: IntoIterator<Item = S>,
158     {
159         RegexSetBuilder::new(exprs).build()
160     }
161 
162     /// Create a new empty regex set.
163     ///
164     /// An empty regex never matches anything.
165     ///
166     /// This is a convenience function for `RegexSet::new([])`, but doesn't
167     /// require one to specify the type of the input.
168     ///
169     /// # Example
170     ///
171     /// ```
172     /// use regex::RegexSet;
173     ///
174     /// let set = RegexSet::empty();
175     /// assert!(set.is_empty());
176     /// // an empty set matches nothing
177     /// assert!(!set.is_match(""));
178     /// ```
empty() -> RegexSet179     pub fn empty() -> RegexSet {
180         let empty: [&str; 0] = [];
181         RegexSetBuilder::new(empty).build().unwrap()
182     }
183 
184     /// Returns true if and only if one of the regexes in this set matches
185     /// the haystack given.
186     ///
187     /// This method should be preferred if you only need to test whether any
188     /// of the regexes in the set should match, but don't care about *which*
189     /// regexes matched. This is because the underlying matching engine will
190     /// quit immediately after seeing the first match instead of continuing to
191     /// find all matches.
192     ///
193     /// Note that as with searches using [`Regex`](crate::Regex), the
194     /// expression is unanchored by default. That is, if the regex does not
195     /// start with `^` or `\A`, or end with `$` or `\z`, then it is permitted
196     /// to match anywhere in the haystack.
197     ///
198     /// # Example
199     ///
200     /// Tests whether a set matches somewhere in a haystack:
201     ///
202     /// ```
203     /// use regex::RegexSet;
204     ///
205     /// let set = RegexSet::new([r"\w+", r"\d+"]).unwrap();
206     /// assert!(set.is_match("foo"));
207     /// assert!(!set.is_match("☃"));
208     /// ```
209     #[inline]
is_match(&self, haystack: &str) -> bool210     pub fn is_match(&self, haystack: &str) -> bool {
211         self.is_match_at(haystack, 0)
212     }
213 
214     /// Returns true if and only if one of the regexes in this set matches the
215     /// haystack given, with the search starting at the offset given.
216     ///
217     /// The significance of the starting point is that it takes the surrounding
218     /// context into consideration. For example, the `\A` anchor can only
219     /// match when `start == 0`.
220     ///
221     /// # Panics
222     ///
223     /// This panics when `start >= haystack.len() + 1`.
224     ///
225     /// # Example
226     ///
227     /// This example shows the significance of `start`. Namely, consider a
228     /// haystack `foobar` and a desire to execute a search starting at offset
229     /// `3`. You could search a substring explicitly, but then the look-around
230     /// assertions won't work correctly. Instead, you can use this method to
231     /// specify the start position of a search.
232     ///
233     /// ```
234     /// use regex::RegexSet;
235     ///
236     /// let set = RegexSet::new([r"\bbar\b", r"(?m)^bar$"]).unwrap();
237     /// let hay = "foobar";
238     /// // We get a match here, but it's probably not intended.
239     /// assert!(set.is_match(&hay[3..]));
240     /// // No match because the  assertions take the context into account.
241     /// assert!(!set.is_match_at(hay, 3));
242     /// ```
243     #[inline]
is_match_at(&self, haystack: &str, start: usize) -> bool244     pub fn is_match_at(&self, haystack: &str, start: usize) -> bool {
245         self.meta.is_match(Input::new(haystack).span(start..haystack.len()))
246     }
247 
248     /// Returns the set of regexes that match in the given haystack.
249     ///
250     /// The set returned contains the index of each regex that matches in
251     /// the given haystack. The index is in correspondence with the order of
252     /// regular expressions given to `RegexSet`'s constructor.
253     ///
254     /// The set can also be used to iterate over the matched indices. The order
255     /// of iteration is always ascending with respect to the matching indices.
256     ///
257     /// Note that as with searches using [`Regex`](crate::Regex), the
258     /// expression is unanchored by default. That is, if the regex does not
259     /// start with `^` or `\A`, or end with `$` or `\z`, then it is permitted
260     /// to match anywhere in the haystack.
261     ///
262     /// # Example
263     ///
264     /// Tests which regular expressions match the given haystack:
265     ///
266     /// ```
267     /// use regex::RegexSet;
268     ///
269     /// let set = RegexSet::new([
270     ///     r"\w+",
271     ///     r"\d+",
272     ///     r"\pL+",
273     ///     r"foo",
274     ///     r"bar",
275     ///     r"barfoo",
276     ///     r"foobar",
277     /// ]).unwrap();
278     /// let matches: Vec<_> = set.matches("foobar").into_iter().collect();
279     /// assert_eq!(matches, vec![0, 2, 3, 4, 6]);
280     ///
281     /// // You can also test whether a particular regex matched:
282     /// let matches = set.matches("foobar");
283     /// assert!(!matches.matched(5));
284     /// assert!(matches.matched(6));
285     /// ```
286     #[inline]
matches(&self, haystack: &str) -> SetMatches287     pub fn matches(&self, haystack: &str) -> SetMatches {
288         self.matches_at(haystack, 0)
289     }
290 
291     /// Returns the set of regexes that match in the given haystack.
292     ///
293     /// The set returned contains the index of each regex that matches in
294     /// the given haystack. The index is in correspondence with the order of
295     /// regular expressions given to `RegexSet`'s constructor.
296     ///
297     /// The set can also be used to iterate over the matched indices. The order
298     /// of iteration is always ascending with respect to the matching indices.
299     ///
300     /// The significance of the starting point is that it takes the surrounding
301     /// context into consideration. For example, the `\A` anchor can only
302     /// match when `start == 0`.
303     ///
304     /// # Panics
305     ///
306     /// This panics when `start >= haystack.len() + 1`.
307     ///
308     /// # Example
309     ///
310     /// Tests which regular expressions match the given haystack:
311     ///
312     /// ```
313     /// use regex::RegexSet;
314     ///
315     /// let set = RegexSet::new([r"\bbar\b", r"(?m)^bar$"]).unwrap();
316     /// let hay = "foobar";
317     /// // We get matches here, but it's probably not intended.
318     /// let matches: Vec<_> = set.matches(&hay[3..]).into_iter().collect();
319     /// assert_eq!(matches, vec![0, 1]);
320     /// // No matches because the  assertions take the context into account.
321     /// let matches: Vec<_> = set.matches_at(hay, 3).into_iter().collect();
322     /// assert_eq!(matches, vec![]);
323     /// ```
324     #[inline]
matches_at(&self, haystack: &str, start: usize) -> SetMatches325     pub fn matches_at(&self, haystack: &str, start: usize) -> SetMatches {
326         let input = Input::new(haystack).span(start..haystack.len());
327         let mut patset = PatternSet::new(self.meta.pattern_len());
328         self.meta.which_overlapping_matches(&input, &mut patset);
329         SetMatches(patset)
330     }
331 
332     /// Returns the same as matches, but starts the search at the given
333     /// offset and stores the matches into the slice given.
334     ///
335     /// The significance of the starting point is that it takes the surrounding
336     /// context into consideration. For example, the `\A` anchor can only
337     /// match when `start == 0`.
338     ///
339     /// `matches` must have a length that is at least the number of regexes
340     /// in this set.
341     ///
342     /// This method returns true if and only if at least one member of
343     /// `matches` is true after executing the set against `haystack`.
344     #[doc(hidden)]
345     #[inline]
matches_read_at( &self, matches: &mut [bool], haystack: &str, start: usize, ) -> bool346     pub fn matches_read_at(
347         &self,
348         matches: &mut [bool],
349         haystack: &str,
350         start: usize,
351     ) -> bool {
352         // This is pretty dumb. We should try to fix this, but the
353         // regex-automata API doesn't provide a way to store matches in an
354         // arbitrary &mut [bool]. Thankfully, this API is is doc(hidden) and
355         // thus not public... But regex-capi currently uses it. We should
356         // fix regex-capi to use a PatternSet, maybe? Not sure... PatternSet
357         // is in regex-automata, not regex. So maybe we should just accept a
358         // 'SetMatches', which is basically just a newtype around PatternSet.
359         let mut patset = PatternSet::new(self.meta.pattern_len());
360         let mut input = Input::new(haystack);
361         input.set_start(start);
362         self.meta.which_overlapping_matches(&input, &mut patset);
363         for pid in patset.iter() {
364             matches[pid] = true;
365         }
366         !patset.is_empty()
367     }
368 
369     /// An alias for `matches_read_at` to preserve backward compatibility.
370     ///
371     /// The `regex-capi` crate used this method, so to avoid breaking that
372     /// crate, we continue to export it as an undocumented API.
373     #[doc(hidden)]
374     #[inline]
read_matches_at( &self, matches: &mut [bool], haystack: &str, start: usize, ) -> bool375     pub fn read_matches_at(
376         &self,
377         matches: &mut [bool],
378         haystack: &str,
379         start: usize,
380     ) -> bool {
381         self.matches_read_at(matches, haystack, start)
382     }
383 
384     /// Returns the total number of regexes in this set.
385     ///
386     /// # Example
387     ///
388     /// ```
389     /// use regex::RegexSet;
390     ///
391     /// assert_eq!(0, RegexSet::empty().len());
392     /// assert_eq!(1, RegexSet::new([r"[0-9]"]).unwrap().len());
393     /// assert_eq!(2, RegexSet::new([r"[0-9]", r"[a-z]"]).unwrap().len());
394     /// ```
395     #[inline]
len(&self) -> usize396     pub fn len(&self) -> usize {
397         self.meta.pattern_len()
398     }
399 
400     /// Returns `true` if this set contains no regexes.
401     ///
402     /// # Example
403     ///
404     /// ```
405     /// use regex::RegexSet;
406     ///
407     /// assert!(RegexSet::empty().is_empty());
408     /// assert!(!RegexSet::new([r"[0-9]"]).unwrap().is_empty());
409     /// ```
410     #[inline]
is_empty(&self) -> bool411     pub fn is_empty(&self) -> bool {
412         self.meta.pattern_len() == 0
413     }
414 
415     /// Returns the regex patterns that this regex set was constructed from.
416     ///
417     /// This function can be used to determine the pattern for a match. The
418     /// slice returned has exactly as many patterns givens to this regex set,
419     /// and the order of the slice is the same as the order of the patterns
420     /// provided to the set.
421     ///
422     /// # Example
423     ///
424     /// ```
425     /// use regex::RegexSet;
426     ///
427     /// let set = RegexSet::new(&[
428     ///     r"\w+",
429     ///     r"\d+",
430     ///     r"\pL+",
431     ///     r"foo",
432     ///     r"bar",
433     ///     r"barfoo",
434     ///     r"foobar",
435     /// ]).unwrap();
436     /// let matches: Vec<_> = set
437     ///     .matches("foobar")
438     ///     .into_iter()
439     ///     .map(|index| &set.patterns()[index])
440     ///     .collect();
441     /// assert_eq!(matches, vec![r"\w+", r"\pL+", r"foo", r"bar", r"foobar"]);
442     /// ```
443     #[inline]
patterns(&self) -> &[String]444     pub fn patterns(&self) -> &[String] {
445         &self.patterns
446     }
447 }
448 
449 impl Default for RegexSet {
default() -> Self450     fn default() -> Self {
451         RegexSet::empty()
452     }
453 }
454 
455 /// A set of matches returned by a regex set.
456 ///
457 /// Values of this type are constructed by [`RegexSet::matches`].
458 #[derive(Clone, Debug)]
459 pub struct SetMatches(PatternSet);
460 
461 impl SetMatches {
462     /// Whether this set contains any matches.
463     ///
464     /// # Example
465     ///
466     /// ```
467     /// use regex::RegexSet;
468     ///
469     /// let set = RegexSet::new(&[
470     ///     r"[a-z]+@[a-z]+\.(com|org|net)",
471     ///     r"[a-z]+\.(com|org|net)",
472     /// ]).unwrap();
473     /// let matches = set.matches("[email protected]");
474     /// assert!(matches.matched_any());
475     /// ```
476     #[inline]
matched_any(&self) -> bool477     pub fn matched_any(&self) -> bool {
478         !self.0.is_empty()
479     }
480 
481     /// Whether the regex at the given index matched.
482     ///
483     /// The index for a regex is determined by its insertion order upon the
484     /// initial construction of a `RegexSet`, starting at `0`.
485     ///
486     /// # Panics
487     ///
488     /// If `index` is greater than or equal to the number of regexes in the
489     /// original set that produced these matches. Equivalently, when `index`
490     /// is greater than or equal to [`SetMatches::len`].
491     ///
492     /// # Example
493     ///
494     /// ```
495     /// use regex::RegexSet;
496     ///
497     /// let set = RegexSet::new([
498     ///     r"[a-z]+@[a-z]+\.(com|org|net)",
499     ///     r"[a-z]+\.(com|org|net)",
500     /// ]).unwrap();
501     /// let matches = set.matches("example.com");
502     /// assert!(!matches.matched(0));
503     /// assert!(matches.matched(1));
504     /// ```
505     #[inline]
matched(&self, index: usize) -> bool506     pub fn matched(&self, index: usize) -> bool {
507         self.0.contains(PatternID::new_unchecked(index))
508     }
509 
510     /// The total number of regexes in the set that created these matches.
511     ///
512     /// **WARNING:** This always returns the same value as [`RegexSet::len`].
513     /// In particular, it does *not* return the number of elements yielded by
514     /// [`SetMatches::iter`]. The only way to determine the total number of
515     /// matched regexes is to iterate over them.
516     ///
517     /// # Example
518     ///
519     /// Notice that this method returns the total number of regexes in the
520     /// original set, and *not* the total number of regexes that matched.
521     ///
522     /// ```
523     /// use regex::RegexSet;
524     ///
525     /// let set = RegexSet::new([
526     ///     r"[a-z]+@[a-z]+\.(com|org|net)",
527     ///     r"[a-z]+\.(com|org|net)",
528     /// ]).unwrap();
529     /// let matches = set.matches("example.com");
530     /// // Total number of patterns that matched.
531     /// assert_eq!(1, matches.iter().count());
532     /// // Total number of patterns in the set.
533     /// assert_eq!(2, matches.len());
534     /// ```
535     #[inline]
len(&self) -> usize536     pub fn len(&self) -> usize {
537         self.0.capacity()
538     }
539 
540     /// Returns an iterator over the indices of the regexes that matched.
541     ///
542     /// This will always produces matches in ascending order, where the index
543     /// yielded corresponds to the index of the regex that matched with respect
544     /// to its position when initially building the set.
545     ///
546     /// # Example
547     ///
548     /// ```
549     /// use regex::RegexSet;
550     ///
551     /// let set = RegexSet::new([
552     ///     r"[0-9]",
553     ///     r"[a-z]",
554     ///     r"[A-Z]",
555     ///     r"\p{Greek}",
556     /// ]).unwrap();
557     /// let hay = "βa1";
558     /// let matches: Vec<_> = set.matches(hay).iter().collect();
559     /// assert_eq!(matches, vec![0, 1, 3]);
560     /// ```
561     ///
562     /// Note that `SetMatches` also implemnets the `IntoIterator` trait, so
563     /// this method is not always needed. For example:
564     ///
565     /// ```
566     /// use regex::RegexSet;
567     ///
568     /// let set = RegexSet::new([
569     ///     r"[0-9]",
570     ///     r"[a-z]",
571     ///     r"[A-Z]",
572     ///     r"\p{Greek}",
573     /// ]).unwrap();
574     /// let hay = "βa1";
575     /// let mut matches = vec![];
576     /// for index in set.matches(hay) {
577     ///     matches.push(index);
578     /// }
579     /// assert_eq!(matches, vec![0, 1, 3]);
580     /// ```
581     #[inline]
iter(&self) -> SetMatchesIter<'_>582     pub fn iter(&self) -> SetMatchesIter<'_> {
583         SetMatchesIter(self.0.iter())
584     }
585 }
586 
587 impl IntoIterator for SetMatches {
588     type IntoIter = SetMatchesIntoIter;
589     type Item = usize;
590 
into_iter(self) -> Self::IntoIter591     fn into_iter(self) -> Self::IntoIter {
592         let it = 0..self.0.capacity();
593         SetMatchesIntoIter { patset: self.0, it }
594     }
595 }
596 
597 impl<'a> IntoIterator for &'a SetMatches {
598     type IntoIter = SetMatchesIter<'a>;
599     type Item = usize;
600 
into_iter(self) -> Self::IntoIter601     fn into_iter(self) -> Self::IntoIter {
602         self.iter()
603     }
604 }
605 
606 /// An owned iterator over the set of matches from a regex set.
607 ///
608 /// This will always produces matches in ascending order of index, where the
609 /// index corresponds to the index of the regex that matched with respect to
610 /// its position when initially building the set.
611 ///
612 /// This iterator is created by calling `SetMatches::into_iter` via the
613 /// `IntoIterator` trait. This is automatically done in `for` loops.
614 ///
615 /// # Example
616 ///
617 /// ```
618 /// use regex::RegexSet;
619 ///
620 /// let set = RegexSet::new([
621 ///     r"[0-9]",
622 ///     r"[a-z]",
623 ///     r"[A-Z]",
624 ///     r"\p{Greek}",
625 /// ]).unwrap();
626 /// let hay = "βa1";
627 /// let mut matches = vec![];
628 /// for index in set.matches(hay) {
629 ///     matches.push(index);
630 /// }
631 /// assert_eq!(matches, vec![0, 1, 3]);
632 /// ```
633 #[derive(Debug)]
634 pub struct SetMatchesIntoIter {
635     patset: PatternSet,
636     it: core::ops::Range<usize>,
637 }
638 
639 impl Iterator for SetMatchesIntoIter {
640     type Item = usize;
641 
next(&mut self) -> Option<usize>642     fn next(&mut self) -> Option<usize> {
643         loop {
644             let id = self.it.next()?;
645             if self.patset.contains(PatternID::new_unchecked(id)) {
646                 return Some(id);
647             }
648         }
649     }
650 
size_hint(&self) -> (usize, Option<usize>)651     fn size_hint(&self) -> (usize, Option<usize>) {
652         self.it.size_hint()
653     }
654 }
655 
656 impl DoubleEndedIterator for SetMatchesIntoIter {
next_back(&mut self) -> Option<usize>657     fn next_back(&mut self) -> Option<usize> {
658         loop {
659             let id = self.it.next_back()?;
660             if self.patset.contains(PatternID::new_unchecked(id)) {
661                 return Some(id);
662             }
663         }
664     }
665 }
666 
667 impl core::iter::FusedIterator for SetMatchesIntoIter {}
668 
669 /// A borrowed iterator over the set of matches from a regex set.
670 ///
671 /// The lifetime `'a` refers to the lifetime of the [`SetMatches`] value that
672 /// created this iterator.
673 ///
674 /// This will always produces matches in ascending order, where the index
675 /// corresponds to the index of the regex that matched with respect to its
676 /// position when initially building the set.
677 ///
678 /// This iterator is created by the [`SetMatches::iter`] method.
679 #[derive(Clone, Debug)]
680 pub struct SetMatchesIter<'a>(PatternSetIter<'a>);
681 
682 impl<'a> Iterator for SetMatchesIter<'a> {
683     type Item = usize;
684 
next(&mut self) -> Option<usize>685     fn next(&mut self) -> Option<usize> {
686         self.0.next().map(|pid| pid.as_usize())
687     }
688 
size_hint(&self) -> (usize, Option<usize>)689     fn size_hint(&self) -> (usize, Option<usize>) {
690         self.0.size_hint()
691     }
692 }
693 
694 impl<'a> DoubleEndedIterator for SetMatchesIter<'a> {
next_back(&mut self) -> Option<usize>695     fn next_back(&mut self) -> Option<usize> {
696         self.0.next_back().map(|pid| pid.as_usize())
697     }
698 }
699 
700 impl<'a> core::iter::FusedIterator for SetMatchesIter<'a> {}
701 
702 impl core::fmt::Debug for RegexSet {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result703     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
704         write!(f, "RegexSet({:?})", self.patterns())
705     }
706 }
707