Coverage Report

Created: 2025-09-27 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/regex-1.11.1/src/regexset/string.rs
Line
Count
Source
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
/// `foo@example.com` 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("foo@example.com"));
106
///
107
/// // Identify which regexes in the set match.
108
/// let matches: Vec<_> = set.matches("foo@example.com").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
    /// ```
154
0
    pub fn new<I, S>(exprs: I) -> Result<RegexSet, Error>
155
0
    where
156
0
        S: AsRef<str>,
157
0
        I: IntoIterator<Item = S>,
158
    {
159
0
        RegexSetBuilder::new(exprs).build()
160
0
    }
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
    /// ```
179
0
    pub fn empty() -> RegexSet {
180
0
        let empty: [&str; 0] = [];
181
0
        RegexSetBuilder::new(empty).build().unwrap()
182
0
    }
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]
210
0
    pub fn is_match(&self, haystack: &str) -> bool {
211
0
        self.is_match_at(haystack, 0)
212
0
    }
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]
244
0
    pub fn is_match_at(&self, haystack: &str, start: usize) -> bool {
245
0
        self.meta.is_match(Input::new(haystack).span(start..haystack.len()))
246
0
    }
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]
287
0
    pub fn matches(&self, haystack: &str) -> SetMatches {
288
0
        self.matches_at(haystack, 0)
289
0
    }
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]
325
0
    pub fn matches_at(&self, haystack: &str, start: usize) -> SetMatches {
326
0
        let input = Input::new(haystack).span(start..haystack.len());
327
0
        let mut patset = PatternSet::new(self.meta.pattern_len());
328
0
        self.meta.which_overlapping_matches(&input, &mut patset);
329
0
        SetMatches(patset)
330
0
    }
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]
346
0
    pub fn matches_read_at(
347
0
        &self,
348
0
        matches: &mut [bool],
349
0
        haystack: &str,
350
0
        start: usize,
351
0
    ) -> 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 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
0
        let mut patset = PatternSet::new(self.meta.pattern_len());
360
0
        let mut input = Input::new(haystack);
361
0
        input.set_start(start);
362
0
        self.meta.which_overlapping_matches(&input, &mut patset);
363
0
        for pid in patset.iter() {
364
0
            matches[pid] = true;
365
0
        }
366
0
        !patset.is_empty()
367
0
    }
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]
375
0
    pub fn read_matches_at(
376
0
        &self,
377
0
        matches: &mut [bool],
378
0
        haystack: &str,
379
0
        start: usize,
380
0
    ) -> bool {
381
0
        self.matches_read_at(matches, haystack, start)
382
0
    }
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]
396
0
    pub fn len(&self) -> usize {
397
0
        self.meta.pattern_len()
398
0
    }
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]
411
0
    pub fn is_empty(&self) -> bool {
412
0
        self.meta.pattern_len() == 0
413
0
    }
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]
444
0
    pub fn patterns(&self) -> &[String] {
445
0
        &self.patterns
446
0
    }
447
}
448
449
impl Default for RegexSet {
450
0
    fn default() -> Self {
451
0
        RegexSet::empty()
452
0
    }
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("foo@example.com");
474
    /// assert!(matches.matched_any());
475
    /// ```
476
    #[inline]
477
0
    pub fn matched_any(&self) -> bool {
478
0
        !self.0.is_empty()
479
0
    }
480
481
    /// Whether all patterns in this set matched.
482
    ///
483
    /// # Example
484
    ///
485
    /// ```
486
    /// use regex::RegexSet;
487
    ///
488
    /// let set = RegexSet::new(&[
489
    ///     r"^foo",
490
    ///     r"[a-z]+\.com",
491
    /// ]).unwrap();
492
    /// let matches = set.matches("foo.example.com");
493
    /// assert!(matches.matched_all());
494
    /// ```
495
0
    pub fn matched_all(&self) -> bool {
496
0
        self.0.is_full()
497
0
    }
498
499
    /// Whether the regex at the given index matched.
500
    ///
501
    /// The index for a regex is determined by its insertion order upon the
502
    /// initial construction of a `RegexSet`, starting at `0`.
503
    ///
504
    /// # Panics
505
    ///
506
    /// If `index` is greater than or equal to the number of regexes in the
507
    /// original set that produced these matches. Equivalently, when `index`
508
    /// is greater than or equal to [`SetMatches::len`].
509
    ///
510
    /// # Example
511
    ///
512
    /// ```
513
    /// use regex::RegexSet;
514
    ///
515
    /// let set = RegexSet::new([
516
    ///     r"[a-z]+@[a-z]+\.(com|org|net)",
517
    ///     r"[a-z]+\.(com|org|net)",
518
    /// ]).unwrap();
519
    /// let matches = set.matches("example.com");
520
    /// assert!(!matches.matched(0));
521
    /// assert!(matches.matched(1));
522
    /// ```
523
    #[inline]
524
0
    pub fn matched(&self, index: usize) -> bool {
525
0
        self.0.contains(PatternID::new_unchecked(index))
526
0
    }
527
528
    /// The total number of regexes in the set that created these matches.
529
    ///
530
    /// **WARNING:** This always returns the same value as [`RegexSet::len`].
531
    /// In particular, it does *not* return the number of elements yielded by
532
    /// [`SetMatches::iter`]. The only way to determine the total number of
533
    /// matched regexes is to iterate over them.
534
    ///
535
    /// # Example
536
    ///
537
    /// Notice that this method returns the total number of regexes in the
538
    /// original set, and *not* the total number of regexes that matched.
539
    ///
540
    /// ```
541
    /// use regex::RegexSet;
542
    ///
543
    /// let set = RegexSet::new([
544
    ///     r"[a-z]+@[a-z]+\.(com|org|net)",
545
    ///     r"[a-z]+\.(com|org|net)",
546
    /// ]).unwrap();
547
    /// let matches = set.matches("example.com");
548
    /// // Total number of patterns that matched.
549
    /// assert_eq!(1, matches.iter().count());
550
    /// // Total number of patterns in the set.
551
    /// assert_eq!(2, matches.len());
552
    /// ```
553
    #[inline]
554
0
    pub fn len(&self) -> usize {
555
0
        self.0.capacity()
556
0
    }
557
558
    /// Returns an iterator over the indices of the regexes that matched.
559
    ///
560
    /// This will always produces matches in ascending order, where the index
561
    /// yielded corresponds to the index of the regex that matched with respect
562
    /// to its position when initially building the set.
563
    ///
564
    /// # Example
565
    ///
566
    /// ```
567
    /// use regex::RegexSet;
568
    ///
569
    /// let set = RegexSet::new([
570
    ///     r"[0-9]",
571
    ///     r"[a-z]",
572
    ///     r"[A-Z]",
573
    ///     r"\p{Greek}",
574
    /// ]).unwrap();
575
    /// let hay = "βa1";
576
    /// let matches: Vec<_> = set.matches(hay).iter().collect();
577
    /// assert_eq!(matches, vec![0, 1, 3]);
578
    /// ```
579
    ///
580
    /// Note that `SetMatches` also implemnets the `IntoIterator` trait, so
581
    /// this method is not always needed. For example:
582
    ///
583
    /// ```
584
    /// use regex::RegexSet;
585
    ///
586
    /// let set = RegexSet::new([
587
    ///     r"[0-9]",
588
    ///     r"[a-z]",
589
    ///     r"[A-Z]",
590
    ///     r"\p{Greek}",
591
    /// ]).unwrap();
592
    /// let hay = "βa1";
593
    /// let mut matches = vec![];
594
    /// for index in set.matches(hay) {
595
    ///     matches.push(index);
596
    /// }
597
    /// assert_eq!(matches, vec![0, 1, 3]);
598
    /// ```
599
    #[inline]
600
0
    pub fn iter(&self) -> SetMatchesIter<'_> {
601
0
        SetMatchesIter(self.0.iter())
602
0
    }
603
}
604
605
impl IntoIterator for SetMatches {
606
    type IntoIter = SetMatchesIntoIter;
607
    type Item = usize;
608
609
0
    fn into_iter(self) -> Self::IntoIter {
610
0
        let it = 0..self.0.capacity();
611
0
        SetMatchesIntoIter { patset: self.0, it }
612
0
    }
613
}
614
615
impl<'a> IntoIterator for &'a SetMatches {
616
    type IntoIter = SetMatchesIter<'a>;
617
    type Item = usize;
618
619
0
    fn into_iter(self) -> Self::IntoIter {
620
0
        self.iter()
621
0
    }
622
}
623
624
/// An owned iterator over the set of matches from a regex set.
625
///
626
/// This will always produces matches in ascending order of index, where the
627
/// index corresponds to the index of the regex that matched with respect to
628
/// its position when initially building the set.
629
///
630
/// This iterator is created by calling `SetMatches::into_iter` via the
631
/// `IntoIterator` trait. This is automatically done in `for` loops.
632
///
633
/// # Example
634
///
635
/// ```
636
/// use regex::RegexSet;
637
///
638
/// let set = RegexSet::new([
639
///     r"[0-9]",
640
///     r"[a-z]",
641
///     r"[A-Z]",
642
///     r"\p{Greek}",
643
/// ]).unwrap();
644
/// let hay = "βa1";
645
/// let mut matches = vec![];
646
/// for index in set.matches(hay) {
647
///     matches.push(index);
648
/// }
649
/// assert_eq!(matches, vec![0, 1, 3]);
650
/// ```
651
#[derive(Debug)]
652
pub struct SetMatchesIntoIter {
653
    patset: PatternSet,
654
    it: core::ops::Range<usize>,
655
}
656
657
impl Iterator for SetMatchesIntoIter {
658
    type Item = usize;
659
660
0
    fn next(&mut self) -> Option<usize> {
661
        loop {
662
0
            let id = self.it.next()?;
663
0
            if self.patset.contains(PatternID::new_unchecked(id)) {
664
0
                return Some(id);
665
0
            }
666
        }
667
0
    }
668
669
0
    fn size_hint(&self) -> (usize, Option<usize>) {
670
0
        self.it.size_hint()
671
0
    }
672
}
673
674
impl DoubleEndedIterator for SetMatchesIntoIter {
675
0
    fn next_back(&mut self) -> Option<usize> {
676
        loop {
677
0
            let id = self.it.next_back()?;
678
0
            if self.patset.contains(PatternID::new_unchecked(id)) {
679
0
                return Some(id);
680
0
            }
681
        }
682
0
    }
683
}
684
685
impl core::iter::FusedIterator for SetMatchesIntoIter {}
686
687
/// A borrowed iterator over the set of matches from a regex set.
688
///
689
/// The lifetime `'a` refers to the lifetime of the [`SetMatches`] value that
690
/// created this iterator.
691
///
692
/// This will always produces matches in ascending order, where the index
693
/// corresponds to the index of the regex that matched with respect to its
694
/// position when initially building the set.
695
///
696
/// This iterator is created by the [`SetMatches::iter`] method.
697
#[derive(Clone, Debug)]
698
pub struct SetMatchesIter<'a>(PatternSetIter<'a>);
699
700
impl<'a> Iterator for SetMatchesIter<'a> {
701
    type Item = usize;
702
703
0
    fn next(&mut self) -> Option<usize> {
704
0
        self.0.next().map(|pid| pid.as_usize())
705
0
    }
706
707
0
    fn size_hint(&self) -> (usize, Option<usize>) {
708
0
        self.0.size_hint()
709
0
    }
710
}
711
712
impl<'a> DoubleEndedIterator for SetMatchesIter<'a> {
713
0
    fn next_back(&mut self) -> Option<usize> {
714
0
        self.0.next_back().map(|pid| pid.as_usize())
715
0
    }
716
}
717
718
impl<'a> core::iter::FusedIterator for SetMatchesIter<'a> {}
719
720
impl core::fmt::Debug for RegexSet {
721
0
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
722
0
        write!(f, "RegexSet({:?})", self.patterns())
723
0
    }
724
}