/rust/registry/src/index.crates.io-1949cf8c6b5b557f/regex-1.5.6/src/re_trait.rs
Line | Count | Source |
1 | | use std::fmt; |
2 | | use std::iter::FusedIterator; |
3 | | |
4 | | /// Slot is a single saved capture location. Note that there are two slots for |
5 | | /// every capture in a regular expression (one slot each for the start and end |
6 | | /// of the capture). |
7 | | pub type Slot = Option<usize>; |
8 | | |
9 | | /// Locations represents the offsets of each capturing group in a regex for |
10 | | /// a single match. |
11 | | /// |
12 | | /// Unlike `Captures`, a `Locations` value only stores offsets. |
13 | | #[doc(hidden)] |
14 | | #[derive(Clone, Debug)] |
15 | | pub struct Locations(Vec<Slot>); |
16 | | |
17 | | impl Locations { |
18 | | /// Returns the start and end positions of the Nth capture group. Returns |
19 | | /// `None` if `i` is not a valid capture group or if the capture group did |
20 | | /// not match anything. The positions returned are *always* byte indices |
21 | | /// with respect to the original string matched. |
22 | 65.0k | pub fn pos(&self, i: usize) -> Option<(usize, usize)> { |
23 | 65.0k | let (s, e) = (i * 2, i * 2 + 1); |
24 | 65.0k | match (self.0.get(s), self.0.get(e)) { |
25 | 40.4k | (Some(&Some(s)), Some(&Some(e))) => Some((s, e)), |
26 | 24.6k | _ => None, |
27 | | } |
28 | 65.0k | } <regex::re_trait::Locations>::pos Line | Count | Source | 22 | 8.78k | pub fn pos(&self, i: usize) -> Option<(usize, usize)> { | 23 | 8.78k | let (s, e) = (i * 2, i * 2 + 1); | 24 | 8.78k | match (self.0.get(s), self.0.get(e)) { | 25 | 5.32k | (Some(&Some(s)), Some(&Some(e))) => Some((s, e)), | 26 | 3.45k | _ => None, | 27 | | } | 28 | 8.78k | } |
<regex::re_trait::Locations>::pos Line | Count | Source | 22 | 56.3k | pub fn pos(&self, i: usize) -> Option<(usize, usize)> { | 23 | 56.3k | let (s, e) = (i * 2, i * 2 + 1); | 24 | 56.3k | match (self.0.get(s), self.0.get(e)) { | 25 | 35.0k | (Some(&Some(s)), Some(&Some(e))) => Some((s, e)), | 26 | 21.2k | _ => None, | 27 | | } | 28 | 56.3k | } |
|
29 | | |
30 | | /// Creates an iterator of all the capture group positions in order of |
31 | | /// appearance in the regular expression. Positions are byte indices |
32 | | /// in terms of the original string matched. |
33 | 0 | pub fn iter(&self) -> SubCapturesPosIter<'_> { |
34 | 0 | SubCapturesPosIter { idx: 0, locs: self } |
35 | 0 | } Unexecuted instantiation: <regex::re_trait::Locations>::iter Unexecuted instantiation: <regex::re_trait::Locations>::iter |
36 | | |
37 | | /// Returns the total number of capturing groups. |
38 | | /// |
39 | | /// This is always at least `1` since every regex has at least `1` |
40 | | /// capturing group that corresponds to the entire match. |
41 | 0 | pub fn len(&self) -> usize { |
42 | 0 | self.0.len() / 2 |
43 | 0 | } Unexecuted instantiation: <regex::re_trait::Locations>::len Unexecuted instantiation: <regex::re_trait::Locations>::len |
44 | | |
45 | | /// Return the individual slots as a slice. |
46 | 66.6k | pub(crate) fn as_slots(&mut self) -> &mut [Slot] { |
47 | 66.6k | &mut self.0 |
48 | 66.6k | } <regex::re_trait::Locations>::as_slots Line | Count | Source | 46 | 9.11k | pub(crate) fn as_slots(&mut self) -> &mut [Slot] { | 47 | 9.11k | &mut self.0 | 48 | 9.11k | } |
<regex::re_trait::Locations>::as_slots Line | Count | Source | 46 | 57.5k | pub(crate) fn as_slots(&mut self) -> &mut [Slot] { | 47 | 57.5k | &mut self.0 | 48 | 57.5k | } |
|
49 | | } |
50 | | |
51 | | /// An iterator over capture group positions for a particular match of a |
52 | | /// regular expression. |
53 | | /// |
54 | | /// Positions are byte indices in terms of the original string matched. |
55 | | /// |
56 | | /// `'c` is the lifetime of the captures. |
57 | | #[derive(Clone, Debug)] |
58 | | pub struct SubCapturesPosIter<'c> { |
59 | | idx: usize, |
60 | | locs: &'c Locations, |
61 | | } |
62 | | |
63 | | impl<'c> Iterator for SubCapturesPosIter<'c> { |
64 | | type Item = Option<(usize, usize)>; |
65 | | |
66 | 0 | fn next(&mut self) -> Option<Option<(usize, usize)>> { |
67 | 0 | if self.idx >= self.locs.len() { |
68 | 0 | return None; |
69 | 0 | } |
70 | 0 | let x = match self.locs.pos(self.idx) { |
71 | 0 | None => Some(None), |
72 | 0 | Some((s, e)) => Some(Some((s, e))), |
73 | | }; |
74 | 0 | self.idx += 1; |
75 | 0 | x |
76 | 0 | } Unexecuted instantiation: <regex::re_trait::SubCapturesPosIter as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <regex::re_trait::SubCapturesPosIter as core::iter::traits::iterator::Iterator>::next |
77 | | } |
78 | | |
79 | | impl<'c> FusedIterator for SubCapturesPosIter<'c> {} |
80 | | |
81 | | /// `RegularExpression` describes types that can implement regex searching. |
82 | | /// |
83 | | /// This trait is my attempt at reducing code duplication and to standardize |
84 | | /// the internal API. Specific duplication that is avoided are the `find` |
85 | | /// and `capture` iterators, which are slightly tricky. |
86 | | /// |
87 | | /// It's not clear whether this trait is worth it, and it also isn't |
88 | | /// clear whether it's useful as a public trait or not. Methods like |
89 | | /// `next_after_empty` reak of bad design, but the rest of the methods seem |
90 | | /// somewhat reasonable. One particular thing this trait would expose would be |
91 | | /// the ability to start the search of a regex anywhere in a haystack, which |
92 | | /// isn't possible in the current public API. |
93 | | pub trait RegularExpression: Sized + fmt::Debug { |
94 | | /// The type of the haystack. |
95 | | type Text: ?Sized + fmt::Debug; |
96 | | |
97 | | /// The number of capture slots in the compiled regular expression. This is |
98 | | /// always two times the number of capture groups (two slots per group). |
99 | | fn slots_len(&self) -> usize; |
100 | | |
101 | | /// Allocates fresh space for all capturing groups in this regex. |
102 | 66.6k | fn locations(&self) -> Locations { |
103 | 66.6k | Locations(vec![None; self.slots_len()]) |
104 | 66.6k | } Unexecuted instantiation: <regex::exec::ExecNoSync as regex::re_trait::RegularExpression>::locations <regex::exec::ExecNoSyncStr as regex::re_trait::RegularExpression>::locations Line | Count | Source | 102 | 9.11k | fn locations(&self) -> Locations { | 103 | 9.11k | Locations(vec![None; self.slots_len()]) | 104 | 9.11k | } |
Unexecuted instantiation: <regex::exec::ExecNoSync as regex::re_trait::RegularExpression>::locations <regex::exec::ExecNoSyncStr as regex::re_trait::RegularExpression>::locations Line | Count | Source | 102 | 57.5k | fn locations(&self) -> Locations { | 103 | 57.5k | Locations(vec![None; self.slots_len()]) | 104 | 57.5k | } |
|
105 | | |
106 | | /// Returns the position of the next character after `i`. |
107 | | /// |
108 | | /// For example, a haystack with type `&[u8]` probably returns `i+1`, |
109 | | /// whereas a haystack with type `&str` probably returns `i` plus the |
110 | | /// length of the next UTF-8 sequence. |
111 | | fn next_after_empty(&self, text: &Self::Text, i: usize) -> usize; |
112 | | |
113 | | /// Returns the location of the shortest match. |
114 | | fn shortest_match_at( |
115 | | &self, |
116 | | text: &Self::Text, |
117 | | start: usize, |
118 | | ) -> Option<usize>; |
119 | | |
120 | | /// Returns whether the regex matches the text given. |
121 | | fn is_match_at(&self, text: &Self::Text, start: usize) -> bool; |
122 | | |
123 | | /// Returns the leftmost-first match location if one exists. |
124 | | fn find_at( |
125 | | &self, |
126 | | text: &Self::Text, |
127 | | start: usize, |
128 | | ) -> Option<(usize, usize)>; |
129 | | |
130 | | /// Returns the leftmost-first match location if one exists, and also |
131 | | /// fills in any matching capture slot locations. |
132 | | fn captures_read_at( |
133 | | &self, |
134 | | locs: &mut Locations, |
135 | | text: &Self::Text, |
136 | | start: usize, |
137 | | ) -> Option<(usize, usize)>; |
138 | | |
139 | | /// Returns an iterator over all non-overlapping successive leftmost-first |
140 | | /// matches. |
141 | 0 | fn find_iter(self, text: &Self::Text) -> Matches<'_, Self> { |
142 | 0 | Matches { re: self, text: text, last_end: 0, last_match: None } |
143 | 0 | } Unexecuted instantiation: <regex::exec::ExecNoSync as regex::re_trait::RegularExpression>::find_iter Unexecuted instantiation: <regex::exec::ExecNoSyncStr as regex::re_trait::RegularExpression>::find_iter Unexecuted instantiation: <regex::exec::ExecNoSync as regex::re_trait::RegularExpression>::find_iter Unexecuted instantiation: <regex::exec::ExecNoSyncStr as regex::re_trait::RegularExpression>::find_iter |
144 | | |
145 | | /// Returns an iterator over all non-overlapping successive leftmost-first |
146 | | /// matches with captures. |
147 | 0 | fn captures_iter(self, text: &Self::Text) -> CaptureMatches<'_, Self> { |
148 | 0 | CaptureMatches(self.find_iter(text)) |
149 | 0 | } Unexecuted instantiation: <regex::exec::ExecNoSync as regex::re_trait::RegularExpression>::captures_iter Unexecuted instantiation: <regex::exec::ExecNoSyncStr as regex::re_trait::RegularExpression>::captures_iter Unexecuted instantiation: <regex::exec::ExecNoSync as regex::re_trait::RegularExpression>::captures_iter Unexecuted instantiation: <regex::exec::ExecNoSyncStr as regex::re_trait::RegularExpression>::captures_iter |
150 | | } |
151 | | |
152 | | /// An iterator over all non-overlapping successive leftmost-first matches. |
153 | | #[derive(Debug)] |
154 | | pub struct Matches<'t, R> |
155 | | where |
156 | | R: RegularExpression, |
157 | | R::Text: 't, |
158 | | { |
159 | | re: R, |
160 | | text: &'t R::Text, |
161 | | last_end: usize, |
162 | | last_match: Option<usize>, |
163 | | } |
164 | | |
165 | | impl<'t, R> Matches<'t, R> |
166 | | where |
167 | | R: RegularExpression, |
168 | | R::Text: 't, |
169 | | { |
170 | | /// Return the text being searched. |
171 | 0 | pub fn text(&self) -> &'t R::Text { |
172 | 0 | self.text |
173 | 0 | } Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSync>>::text Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSyncStr>>::text Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSync>>::text Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSyncStr>>::text |
174 | | |
175 | | /// Return the underlying regex. |
176 | 0 | pub fn regex(&self) -> &R { |
177 | 0 | &self.re |
178 | 0 | } Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSync>>::regex Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSyncStr>>::regex Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSync>>::regex Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSyncStr>>::regex |
179 | | } |
180 | | |
181 | | impl<'t, R> Iterator for Matches<'t, R> |
182 | | where |
183 | | R: RegularExpression, |
184 | | R::Text: 't + AsRef<[u8]>, |
185 | | { |
186 | | type Item = (usize, usize); |
187 | | |
188 | 0 | fn next(&mut self) -> Option<(usize, usize)> { |
189 | 0 | if self.last_end > self.text.as_ref().len() { |
190 | 0 | return None; |
191 | 0 | } |
192 | 0 | let (s, e) = match self.re.find_at(self.text, self.last_end) { |
193 | 0 | None => return None, |
194 | 0 | Some((s, e)) => (s, e), |
195 | | }; |
196 | 0 | if s == e { |
197 | | // This is an empty match. To ensure we make progress, start |
198 | | // the next search at the smallest possible starting position |
199 | | // of the next match following this one. |
200 | 0 | self.last_end = self.re.next_after_empty(self.text, e); |
201 | | // Don't accept empty matches immediately following a match. |
202 | | // Just move on to the next match. |
203 | 0 | if Some(e) == self.last_match { |
204 | 0 | return self.next(); |
205 | 0 | } |
206 | 0 | } else { |
207 | 0 | self.last_end = e; |
208 | 0 | } |
209 | 0 | self.last_match = Some(e); |
210 | 0 | Some((s, e)) |
211 | 0 | } Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSync> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSyncStr> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSync> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <regex::re_trait::Matches<regex::exec::ExecNoSyncStr> as core::iter::traits::iterator::Iterator>::next |
212 | | } |
213 | | |
214 | | impl<'t, R> FusedIterator for Matches<'t, R> |
215 | | where |
216 | | R: RegularExpression, |
217 | | R::Text: 't + AsRef<[u8]>, |
218 | | { |
219 | | } |
220 | | |
221 | | /// An iterator over all non-overlapping successive leftmost-first matches with |
222 | | /// captures. |
223 | | #[derive(Debug)] |
224 | | pub struct CaptureMatches<'t, R>(Matches<'t, R>) |
225 | | where |
226 | | R: RegularExpression, |
227 | | R::Text: 't; |
228 | | |
229 | | impl<'t, R> CaptureMatches<'t, R> |
230 | | where |
231 | | R: RegularExpression, |
232 | | R::Text: 't, |
233 | | { |
234 | | /// Return the text being searched. |
235 | 0 | pub fn text(&self) -> &'t R::Text { |
236 | 0 | self.0.text() |
237 | 0 | } Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSync>>::text Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSyncStr>>::text Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSync>>::text Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSyncStr>>::text |
238 | | |
239 | | /// Return the underlying regex. |
240 | 0 | pub fn regex(&self) -> &R { |
241 | 0 | self.0.regex() |
242 | 0 | } Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSync>>::regex Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSyncStr>>::regex Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSync>>::regex Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSyncStr>>::regex |
243 | | } |
244 | | |
245 | | impl<'t, R> Iterator for CaptureMatches<'t, R> |
246 | | where |
247 | | R: RegularExpression, |
248 | | R::Text: 't + AsRef<[u8]>, |
249 | | { |
250 | | type Item = Locations; |
251 | | |
252 | 0 | fn next(&mut self) -> Option<Locations> { |
253 | 0 | if self.0.last_end > self.0.text.as_ref().len() { |
254 | 0 | return None; |
255 | 0 | } |
256 | 0 | let mut locs = self.0.re.locations(); |
257 | 0 | let (s, e) = match self.0.re.captures_read_at( |
258 | 0 | &mut locs, |
259 | 0 | self.0.text, |
260 | 0 | self.0.last_end, |
261 | 0 | ) { |
262 | 0 | None => return None, |
263 | 0 | Some((s, e)) => (s, e), |
264 | | }; |
265 | 0 | if s == e { |
266 | 0 | self.0.last_end = self.0.re.next_after_empty(self.0.text, e); |
267 | 0 | if Some(e) == self.0.last_match { |
268 | 0 | return self.next(); |
269 | 0 | } |
270 | 0 | } else { |
271 | 0 | self.0.last_end = e; |
272 | 0 | } |
273 | 0 | self.0.last_match = Some(e); |
274 | 0 | Some(locs) |
275 | 0 | } Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSync> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSyncStr> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSync> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <regex::re_trait::CaptureMatches<regex::exec::ExecNoSyncStr> as core::iter::traits::iterator::Iterator>::next |
276 | | } |
277 | | |
278 | | impl<'t, R> FusedIterator for CaptureMatches<'t, R> |
279 | | where |
280 | | R: RegularExpression, |
281 | | R::Text: 't + AsRef<[u8]>, |
282 | | { |
283 | | } |