1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//! Multi-pattern RegSet (same encoding).
extern crate alloc;
use alloc::vec::Vec;
use super::error::{Error, ErrorKind};
use super::param::MatchParam;
use super::region::Region;
use super::Regex;
/// Set of compiled regexes. All must share an encoding. FIND_LONGEST is refused.
pub struct RegSet {
regs: Vec<Regex>,
}
impl RegSet {
pub fn new(regs: Vec<Regex>) -> Result<Self, Error> {
if let Some(first) = regs.first() {
let enc = first.encoding();
for r in ®s {
if r.encoding() != enc {
return Err(Error::kind_msg(
ErrorKind::InvalidArgument,
"regset encodings differ",
));
}
if r.options().contains(super::syntax::Options::FIND_LONGEST) {
return Err(Error::kind_msg(
ErrorKind::InvalidArgument,
"FIND_LONGEST not allowed in regset",
));
}
}
}
Ok(Self { regs })
}
pub fn add(&mut self, re: Regex) -> Result<(), Error> {
if let Some(first) = self.regs.first() {
if first.encoding() != re.encoding() {
return Err(Error::kind_msg(
ErrorKind::InvalidArgument,
"regset encodings differ",
));
}
}
self.regs.push(re);
Ok(())
}
/// How many patterns are in the set.
pub fn len(&self) -> usize {
self.regs.len()
}
/// True when the set holds no patterns.
///
/// A `RegSet` with a public `len` and no `is_empty` is a Rust API that
/// reads wrong at every call site; searching an empty set matches nothing.
pub fn is_empty(&self) -> bool {
self.regs.is_empty()
}
pub fn get(&self, i: usize) -> Option<&Regex> {
self.regs.get(i)
}
/// Search all patterns; return (index, region) of the leftmost match
/// (Oniguruma lead: position then index).
pub fn search(
&self,
hay: &[u8],
param: &MatchParam,
) -> Result<Option<(usize, Region)>, Error> {
let mut best: Option<(usize, Region)> = None;
for (i, re) in self.regs.iter().enumerate() {
if let Some(r) = re.search_param(hay, param)? {
let better = match &best {
None => true,
Some((_, b)) => r.range().start < b.range().start,
};
if better {
best = Some((i, r));
}
}
}
Ok(best)
}
}