]>
Commit | Line | Data |
---|---|---|
c34b1796 AL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
9346a6ac AL |
11 | //! The string Pattern API. |
12 | //! | |
13 | //! For more details, see the traits `Pattern`, `Searcher`, | |
14 | //! `ReverseSearcher` and `DoubleEndedSearcher`. | |
15 | ||
62682a34 SL |
16 | #![unstable(feature = "pattern", |
17 | reason = "API not fully fleshed out and ready to be stabilized")] | |
18 | ||
c34b1796 AL |
19 | use prelude::*; |
20 | ||
21 | // Pattern | |
22 | ||
23 | /// A string pattern. | |
24 | /// | |
25 | /// A `Pattern<'a>` expresses that the implementing type | |
26 | /// can be used as a string pattern for searching in a `&'a str`. | |
27 | /// | |
28 | /// For example, both `'a'` and `"aa"` are patterns that | |
29 | /// would match at index `1` in the string `"baaaab"`. | |
30 | /// | |
31 | /// The trait itself acts as a builder for an associated | |
32 | /// `Searcher` type, which does the actual work of finding | |
33 | /// occurrences of the pattern in a string. | |
34 | pub trait Pattern<'a>: Sized { | |
35 | /// Associated searcher for this pattern | |
36 | type Searcher: Searcher<'a>; | |
37 | ||
9346a6ac | 38 | /// Constructs the associated searcher from |
c34b1796 AL |
39 | /// `self` and the `haystack` to search in. |
40 | fn into_searcher(self, haystack: &'a str) -> Self::Searcher; | |
41 | ||
9346a6ac | 42 | /// Checks whether the pattern matches anywhere in the haystack |
c34b1796 AL |
43 | #[inline] |
44 | fn is_contained_in(self, haystack: &'a str) -> bool { | |
45 | self.into_searcher(haystack).next_match().is_some() | |
46 | } | |
47 | ||
9346a6ac | 48 | /// Checks whether the pattern matches at the front of the haystack |
c34b1796 AL |
49 | #[inline] |
50 | fn is_prefix_of(self, haystack: &'a str) -> bool { | |
51 | match self.into_searcher(haystack).next() { | |
52 | SearchStep::Match(0, _) => true, | |
53 | _ => false, | |
54 | } | |
55 | } | |
56 | ||
9346a6ac | 57 | /// Checks whether the pattern matches at the back of the haystack |
c34b1796 AL |
58 | #[inline] |
59 | fn is_suffix_of(self, haystack: &'a str) -> bool | |
60 | where Self::Searcher: ReverseSearcher<'a> | |
61 | { | |
62 | match self.into_searcher(haystack).next_back() { | |
63 | SearchStep::Match(_, j) if haystack.len() == j => true, | |
64 | _ => false, | |
65 | } | |
66 | } | |
67 | } | |
68 | ||
69 | // Searcher | |
70 | ||
71 | /// Result of calling `Searcher::next()` or `ReverseSearcher::next_back()`. | |
72 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | |
73 | pub enum SearchStep { | |
74 | /// Expresses that a match of the pattern has been found at | |
75 | /// `haystack[a..b]`. | |
76 | Match(usize, usize), | |
77 | /// Expresses that `haystack[a..b]` has been rejected as a possible match | |
78 | /// of the pattern. | |
79 | /// | |
80 | /// Note that there might be more than one `Reject` between two `Match`es, | |
81 | /// there is no requirement for them to be combined into one. | |
82 | Reject(usize, usize), | |
83 | /// Expresses that every byte of the haystack has been visted, ending | |
84 | /// the iteration. | |
85 | Done | |
86 | } | |
87 | ||
88 | /// A searcher for a string pattern. | |
89 | /// | |
90 | /// This trait provides methods for searching for non-overlapping | |
91 | /// matches of a pattern starting from the front (left) of a string. | |
92 | /// | |
93 | /// It will be implemented by associated `Searcher` | |
94 | /// types of the `Pattern` trait. | |
95 | /// | |
96 | /// The trait is marked unsafe because the indices returned by the | |
97 | /// `next()` methods are required to lie on valid utf8 boundaries in | |
98 | /// the haystack. This enables consumers of this trait to | |
99 | /// slice the haystack without additional runtime checks. | |
100 | pub unsafe trait Searcher<'a> { | |
101 | /// Getter for the underlaying string to be searched in | |
102 | /// | |
103 | /// Will always return the same `&str` | |
104 | fn haystack(&self) -> &'a str; | |
105 | ||
106 | /// Performs the next search step starting from the front. | |
107 | /// | |
108 | /// - Returns `Match(a, b)` if `haystack[a..b]` matches the pattern. | |
109 | /// - Returns `Reject(a, b)` if `haystack[a..b]` can not match the | |
110 | /// pattern, even partially. | |
111 | /// - Returns `Done` if every byte of the haystack has been visited | |
112 | /// | |
113 | /// The stream of `Match` and `Reject` values up to a `Done` | |
114 | /// will contain index ranges that are adjacent, non-overlapping, | |
115 | /// covering the whole haystack, and laying on utf8 boundaries. | |
116 | /// | |
117 | /// A `Match` result needs to contain the whole matched pattern, | |
118 | /// however `Reject` results may be split up into arbitrary | |
119 | /// many adjacent fragments. Both ranges may have zero length. | |
120 | /// | |
121 | /// As an example, the pattern `"aaa"` and the haystack `"cbaaaaab"` | |
122 | /// might produce the stream | |
123 | /// `[Reject(0, 1), Reject(1, 2), Match(2, 5), Reject(5, 8)]` | |
124 | fn next(&mut self) -> SearchStep; | |
125 | ||
126 | /// Find the next `Match` result. See `next()` | |
127 | #[inline] | |
128 | fn next_match(&mut self) -> Option<(usize, usize)> { | |
129 | loop { | |
130 | match self.next() { | |
131 | SearchStep::Match(a, b) => return Some((a, b)), | |
132 | SearchStep::Done => return None, | |
133 | _ => continue, | |
134 | } | |
135 | } | |
136 | } | |
137 | ||
138 | /// Find the next `Reject` result. See `next()` | |
139 | #[inline] | |
140 | fn next_reject(&mut self) -> Option<(usize, usize)> { | |
141 | loop { | |
142 | match self.next() { | |
143 | SearchStep::Reject(a, b) => return Some((a, b)), | |
144 | SearchStep::Done => return None, | |
145 | _ => continue, | |
146 | } | |
147 | } | |
148 | } | |
149 | } | |
150 | ||
151 | /// A reverse searcher for a string pattern. | |
152 | /// | |
153 | /// This trait provides methods for searching for non-overlapping | |
154 | /// matches of a pattern starting from the back (right) of a string. | |
155 | /// | |
156 | /// It will be implemented by associated `Searcher` | |
157 | /// types of the `Pattern` trait if the pattern supports searching | |
158 | /// for it from the back. | |
159 | /// | |
160 | /// The index ranges returned by this trait are not required | |
161 | /// to exactly match those of the forward search in reverse. | |
162 | /// | |
163 | /// For the reason why this trait is marked unsafe, see them | |
164 | /// parent trait `Searcher`. | |
165 | pub unsafe trait ReverseSearcher<'a>: Searcher<'a> { | |
166 | /// Performs the next search step starting from the back. | |
167 | /// | |
168 | /// - Returns `Match(a, b)` if `haystack[a..b]` matches the pattern. | |
169 | /// - Returns `Reject(a, b)` if `haystack[a..b]` can not match the | |
170 | /// pattern, even partially. | |
171 | /// - Returns `Done` if every byte of the haystack has been visited | |
172 | /// | |
173 | /// The stream of `Match` and `Reject` values up to a `Done` | |
174 | /// will contain index ranges that are adjacent, non-overlapping, | |
175 | /// covering the whole haystack, and laying on utf8 boundaries. | |
176 | /// | |
177 | /// A `Match` result needs to contain the whole matched pattern, | |
178 | /// however `Reject` results may be split up into arbitrary | |
179 | /// many adjacent fragments. Both ranges may have zero length. | |
180 | /// | |
181 | /// As an example, the pattern `"aaa"` and the haystack `"cbaaaaab"` | |
182 | /// might produce the stream | |
183 | /// `[Reject(7, 8), Match(4, 7), Reject(1, 4), Reject(0, 1)]` | |
184 | fn next_back(&mut self) -> SearchStep; | |
185 | ||
186 | /// Find the next `Match` result. See `next_back()` | |
187 | #[inline] | |
188 | fn next_match_back(&mut self) -> Option<(usize, usize)>{ | |
189 | loop { | |
190 | match self.next_back() { | |
191 | SearchStep::Match(a, b) => return Some((a, b)), | |
192 | SearchStep::Done => return None, | |
193 | _ => continue, | |
194 | } | |
195 | } | |
196 | } | |
197 | ||
198 | /// Find the next `Reject` result. See `next_back()` | |
199 | #[inline] | |
200 | fn next_reject_back(&mut self) -> Option<(usize, usize)>{ | |
201 | loop { | |
202 | match self.next_back() { | |
203 | SearchStep::Reject(a, b) => return Some((a, b)), | |
204 | SearchStep::Done => return None, | |
205 | _ => continue, | |
206 | } | |
207 | } | |
208 | } | |
209 | } | |
210 | ||
211 | /// A marker trait to express that a `ReverseSearcher` | |
212 | /// can be used for a `DoubleEndedIterator` implementation. | |
213 | /// | |
214 | /// For this, the impl of `Searcher` and `ReverseSearcher` need | |
215 | /// to follow these conditions: | |
216 | /// | |
217 | /// - All results of `next()` need to be identical | |
218 | /// to the results of `next_back()` in reverse order. | |
219 | /// - `next()` and `next_back()` need to behave as | |
220 | /// the two ends of a range of values, that is they | |
221 | /// can not "walk past each other". | |
222 | /// | |
223 | /// # Examples | |
224 | /// | |
225 | /// `char::Searcher` is a `DoubleEndedSearcher` because searching for a | |
226 | /// `char` only requires looking at one at a time, which behaves the same | |
227 | /// from both ends. | |
228 | /// | |
229 | /// `(&str)::Searcher` is not a `DoubleEndedSearcher` because | |
230 | /// the pattern `"aa"` in the haystack `"aaa"` matches as either | |
231 | /// `"[aa]a"` or `"a[aa]"`, depending from which side it is searched. | |
232 | pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {} | |
233 | ||
9346a6ac | 234 | ///////////////////////////////////////////////////////////////////////////// |
c34b1796 | 235 | // Impl for a CharEq wrapper |
9346a6ac | 236 | ///////////////////////////////////////////////////////////////////////////// |
c34b1796 AL |
237 | |
238 | #[doc(hidden)] | |
239 | trait CharEq { | |
240 | fn matches(&mut self, char) -> bool; | |
241 | fn only_ascii(&self) -> bool; | |
242 | } | |
243 | ||
244 | impl CharEq for char { | |
245 | #[inline] | |
246 | fn matches(&mut self, c: char) -> bool { *self == c } | |
247 | ||
248 | #[inline] | |
249 | fn only_ascii(&self) -> bool { (*self as u32) < 128 } | |
250 | } | |
251 | ||
252 | impl<F> CharEq for F where F: FnMut(char) -> bool { | |
253 | #[inline] | |
254 | fn matches(&mut self, c: char) -> bool { (*self)(c) } | |
255 | ||
256 | #[inline] | |
257 | fn only_ascii(&self) -> bool { false } | |
258 | } | |
259 | ||
260 | impl<'a> CharEq for &'a [char] { | |
261 | #[inline] | |
262 | fn matches(&mut self, c: char) -> bool { | |
263 | self.iter().any(|&m| { let mut m = m; m.matches(c) }) | |
264 | } | |
265 | ||
266 | #[inline] | |
267 | fn only_ascii(&self) -> bool { | |
268 | self.iter().all(|m| m.only_ascii()) | |
269 | } | |
270 | } | |
271 | ||
272 | struct CharEqPattern<C: CharEq>(C); | |
273 | ||
9346a6ac | 274 | #[derive(Clone)] |
c34b1796 AL |
275 | struct CharEqSearcher<'a, C: CharEq> { |
276 | char_eq: C, | |
277 | haystack: &'a str, | |
278 | char_indices: super::CharIndices<'a>, | |
279 | #[allow(dead_code)] | |
280 | ascii_only: bool, | |
281 | } | |
282 | ||
283 | impl<'a, C: CharEq> Pattern<'a> for CharEqPattern<C> { | |
284 | type Searcher = CharEqSearcher<'a, C>; | |
285 | ||
286 | #[inline] | |
287 | fn into_searcher(self, haystack: &'a str) -> CharEqSearcher<'a, C> { | |
288 | CharEqSearcher { | |
289 | ascii_only: self.0.only_ascii(), | |
290 | haystack: haystack, | |
291 | char_eq: self.0, | |
292 | char_indices: haystack.char_indices(), | |
293 | } | |
294 | } | |
295 | } | |
296 | ||
297 | unsafe impl<'a, C: CharEq> Searcher<'a> for CharEqSearcher<'a, C> { | |
298 | #[inline] | |
299 | fn haystack(&self) -> &'a str { | |
300 | self.haystack | |
301 | } | |
302 | ||
303 | #[inline] | |
304 | fn next(&mut self) -> SearchStep { | |
305 | let s = &mut self.char_indices; | |
306 | // Compare lengths of the internal byte slice iterator | |
307 | // to find length of current char | |
308 | let (pre_len, _) = s.iter.iter.size_hint(); | |
309 | if let Some((i, c)) = s.next() { | |
310 | let (len, _) = s.iter.iter.size_hint(); | |
311 | let char_len = pre_len - len; | |
312 | if self.char_eq.matches(c) { | |
313 | return SearchStep::Match(i, i + char_len); | |
314 | } else { | |
315 | return SearchStep::Reject(i, i + char_len); | |
316 | } | |
317 | } | |
318 | SearchStep::Done | |
319 | } | |
320 | } | |
321 | ||
322 | unsafe impl<'a, C: CharEq> ReverseSearcher<'a> for CharEqSearcher<'a, C> { | |
323 | #[inline] | |
324 | fn next_back(&mut self) -> SearchStep { | |
325 | let s = &mut self.char_indices; | |
326 | // Compare lengths of the internal byte slice iterator | |
327 | // to find length of current char | |
328 | let (pre_len, _) = s.iter.iter.size_hint(); | |
329 | if let Some((i, c)) = s.next_back() { | |
330 | let (len, _) = s.iter.iter.size_hint(); | |
331 | let char_len = pre_len - len; | |
332 | if self.char_eq.matches(c) { | |
333 | return SearchStep::Match(i, i + char_len); | |
334 | } else { | |
335 | return SearchStep::Reject(i, i + char_len); | |
336 | } | |
337 | } | |
338 | SearchStep::Done | |
339 | } | |
340 | } | |
341 | ||
342 | impl<'a, C: CharEq> DoubleEndedSearcher<'a> for CharEqSearcher<'a, C> {} | |
343 | ||
9346a6ac | 344 | ///////////////////////////////////////////////////////////////////////////// |
c34b1796 | 345 | // Impl for &str |
9346a6ac | 346 | ///////////////////////////////////////////////////////////////////////////// |
c34b1796 AL |
347 | |
348 | // Todo: Optimize the naive implementation here | |
349 | ||
9346a6ac | 350 | /// Associated type for `<&str as Pattern<'a>>::Searcher`. |
c34b1796 | 351 | #[derive(Clone)] |
9346a6ac | 352 | pub struct StrSearcher<'a, 'b> { |
c34b1796 AL |
353 | haystack: &'a str, |
354 | needle: &'b str, | |
355 | start: usize, | |
356 | end: usize, | |
9346a6ac AL |
357 | state: State, |
358 | } | |
359 | ||
360 | #[derive(Clone, PartialEq)] | |
361 | enum State { Done, NotDone, Reject(usize, usize) } | |
362 | impl State { | |
363 | #[inline] fn done(&self) -> bool { *self == State::Done } | |
364 | #[inline] fn take(&mut self) -> State { ::mem::replace(self, State::NotDone) } | |
c34b1796 AL |
365 | } |
366 | ||
367 | /// Non-allocating substring search. | |
368 | /// | |
369 | /// Will handle the pattern `""` as returning empty matches at each utf8 | |
370 | /// boundary. | |
371 | impl<'a, 'b> Pattern<'a> for &'b str { | |
372 | type Searcher = StrSearcher<'a, 'b>; | |
373 | ||
374 | #[inline] | |
375 | fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> { | |
376 | StrSearcher { | |
377 | haystack: haystack, | |
378 | needle: self, | |
379 | start: 0, | |
380 | end: haystack.len(), | |
9346a6ac | 381 | state: State::NotDone, |
c34b1796 AL |
382 | } |
383 | } | |
384 | } | |
385 | ||
386 | unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { | |
387 | #[inline] | |
388 | fn haystack(&self) -> &'a str { | |
389 | self.haystack | |
390 | } | |
391 | ||
392 | #[inline] | |
393 | fn next(&mut self) -> SearchStep { | |
394 | str_search_step(self, | |
395 | |m: &mut StrSearcher| { | |
396 | // Forward step for empty needle | |
397 | let current_start = m.start; | |
9346a6ac | 398 | if !m.state.done() { |
c34b1796 | 399 | m.start = m.haystack.char_range_at(current_start).next; |
9346a6ac | 400 | m.state = State::Reject(current_start, m.start); |
c34b1796 AL |
401 | } |
402 | SearchStep::Match(current_start, current_start) | |
403 | }, | |
404 | |m: &mut StrSearcher| { | |
405 | // Forward step for nonempty needle | |
406 | let current_start = m.start; | |
407 | // Compare byte window because this might break utf8 boundaries | |
408 | let possible_match = &m.haystack.as_bytes()[m.start .. m.start + m.needle.len()]; | |
409 | if possible_match == m.needle.as_bytes() { | |
410 | m.start += m.needle.len(); | |
411 | SearchStep::Match(current_start, m.start) | |
412 | } else { | |
413 | // Skip a char | |
414 | let haystack_suffix = &m.haystack[m.start..]; | |
415 | m.start += haystack_suffix.chars().next().unwrap().len_utf8(); | |
416 | SearchStep::Reject(current_start, m.start) | |
417 | } | |
418 | }) | |
419 | } | |
420 | } | |
421 | ||
422 | unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> { | |
423 | #[inline] | |
424 | fn next_back(&mut self) -> SearchStep { | |
425 | str_search_step(self, | |
426 | |m: &mut StrSearcher| { | |
427 | // Backward step for empty needle | |
428 | let current_end = m.end; | |
9346a6ac | 429 | if !m.state.done() { |
c34b1796 | 430 | m.end = m.haystack.char_range_at_reverse(current_end).next; |
9346a6ac | 431 | m.state = State::Reject(m.end, current_end); |
c34b1796 AL |
432 | } |
433 | SearchStep::Match(current_end, current_end) | |
434 | }, | |
435 | |m: &mut StrSearcher| { | |
436 | // Backward step for nonempty needle | |
437 | let current_end = m.end; | |
438 | // Compare byte window because this might break utf8 boundaries | |
439 | let possible_match = &m.haystack.as_bytes()[m.end - m.needle.len() .. m.end]; | |
440 | if possible_match == m.needle.as_bytes() { | |
441 | m.end -= m.needle.len(); | |
442 | SearchStep::Match(m.end, current_end) | |
443 | } else { | |
444 | // Skip a char | |
445 | let haystack_prefix = &m.haystack[..m.end]; | |
446 | m.end -= haystack_prefix.chars().rev().next().unwrap().len_utf8(); | |
447 | SearchStep::Reject(m.end, current_end) | |
448 | } | |
449 | }) | |
450 | } | |
451 | } | |
452 | ||
453 | // Helper function for encapsulating the common control flow | |
454 | // of doing a search step from the front or doing a search step from the back | |
455 | fn str_search_step<F, G>(mut m: &mut StrSearcher, | |
456 | empty_needle_step: F, | |
457 | nonempty_needle_step: G) -> SearchStep | |
458 | where F: FnOnce(&mut StrSearcher) -> SearchStep, | |
459 | G: FnOnce(&mut StrSearcher) -> SearchStep | |
460 | { | |
9346a6ac | 461 | if m.state.done() { |
c34b1796 | 462 | SearchStep::Done |
9346a6ac | 463 | } else if m.needle.is_empty() && m.start <= m.end { |
c34b1796 | 464 | // Case for needle == "" |
9346a6ac AL |
465 | if let State::Reject(a, b) = m.state.take() { |
466 | SearchStep::Reject(a, b) | |
467 | } else { | |
468 | if m.start == m.end { | |
469 | m.state = State::Done; | |
470 | } | |
471 | empty_needle_step(&mut m) | |
c34b1796 | 472 | } |
c34b1796 AL |
473 | } else if m.start + m.needle.len() <= m.end { |
474 | // Case for needle != "" | |
475 | nonempty_needle_step(&mut m) | |
476 | } else if m.start < m.end { | |
477 | // Remaining slice shorter than needle, reject it | |
9346a6ac | 478 | m.state = State::Done; |
c34b1796 AL |
479 | SearchStep::Reject(m.start, m.end) |
480 | } else { | |
9346a6ac | 481 | m.state = State::Done; |
c34b1796 AL |
482 | SearchStep::Done |
483 | } | |
484 | } | |
485 | ||
9346a6ac AL |
486 | ///////////////////////////////////////////////////////////////////////////// |
487 | ||
488 | macro_rules! pattern_methods { | |
489 | ($t:ty, $pmap:expr, $smap:expr) => { | |
490 | type Searcher = $t; | |
491 | ||
492 | #[inline] | |
493 | fn into_searcher(self, haystack: &'a str) -> $t { | |
494 | ($smap)(($pmap)(self).into_searcher(haystack)) | |
c34b1796 | 495 | } |
9346a6ac | 496 | |
c34b1796 AL |
497 | #[inline] |
498 | fn is_contained_in(self, haystack: &'a str) -> bool { | |
9346a6ac | 499 | ($pmap)(self).is_contained_in(haystack) |
c34b1796 | 500 | } |
9346a6ac | 501 | |
c34b1796 AL |
502 | #[inline] |
503 | fn is_prefix_of(self, haystack: &'a str) -> bool { | |
9346a6ac | 504 | ($pmap)(self).is_prefix_of(haystack) |
c34b1796 | 505 | } |
9346a6ac | 506 | |
c34b1796 AL |
507 | #[inline] |
508 | fn is_suffix_of(self, haystack: &'a str) -> bool | |
9346a6ac | 509 | where $t: ReverseSearcher<'a> |
c34b1796 | 510 | { |
9346a6ac | 511 | ($pmap)(self).is_suffix_of(haystack) |
c34b1796 AL |
512 | } |
513 | } | |
514 | } | |
515 | ||
9346a6ac AL |
516 | macro_rules! searcher_methods { |
517 | (forward) => { | |
518 | #[inline] | |
519 | fn haystack(&self) -> &'a str { | |
520 | self.0.haystack() | |
521 | } | |
522 | #[inline] | |
523 | fn next(&mut self) -> SearchStep { | |
524 | self.0.next() | |
525 | } | |
526 | #[inline] | |
527 | fn next_match(&mut self) -> Option<(usize, usize)> { | |
528 | self.0.next_match() | |
529 | } | |
530 | #[inline] | |
531 | fn next_reject(&mut self) -> Option<(usize, usize)> { | |
532 | self.0.next_reject() | |
533 | } | |
534 | }; | |
535 | (reverse) => { | |
536 | #[inline] | |
537 | fn next_back(&mut self) -> SearchStep { | |
538 | self.0.next_back() | |
539 | } | |
540 | #[inline] | |
541 | fn next_match_back(&mut self) -> Option<(usize, usize)> { | |
542 | self.0.next_match_back() | |
543 | } | |
544 | #[inline] | |
545 | fn next_reject_back(&mut self) -> Option<(usize, usize)> { | |
546 | self.0.next_reject_back() | |
547 | } | |
548 | } | |
c34b1796 AL |
549 | } |
550 | ||
9346a6ac AL |
551 | ///////////////////////////////////////////////////////////////////////////// |
552 | // Impl for char | |
553 | ///////////////////////////////////////////////////////////////////////////// | |
554 | ||
555 | /// Associated type for `<char as Pattern<'a>>::Searcher`. | |
556 | #[derive(Clone)] | |
557 | pub struct CharSearcher<'a>(<CharEqPattern<char> as Pattern<'a>>::Searcher); | |
c34b1796 AL |
558 | |
559 | unsafe impl<'a> Searcher<'a> for CharSearcher<'a> { | |
9346a6ac | 560 | searcher_methods!(forward); |
c34b1796 | 561 | } |
9346a6ac | 562 | |
c34b1796 | 563 | unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> { |
9346a6ac | 564 | searcher_methods!(reverse); |
c34b1796 | 565 | } |
c34b1796 | 566 | |
9346a6ac | 567 | impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {} |
c34b1796 | 568 | |
9346a6ac AL |
569 | /// Searches for chars that are equal to a given char |
570 | impl<'a> Pattern<'a> for char { | |
571 | pattern_methods!(CharSearcher<'a>, CharEqPattern, CharSearcher); | |
c34b1796 AL |
572 | } |
573 | ||
9346a6ac AL |
574 | ///////////////////////////////////////////////////////////////////////////// |
575 | // Impl for &[char] | |
576 | ///////////////////////////////////////////////////////////////////////////// | |
577 | ||
578 | // Todo: Change / Remove due to ambiguity in meaning. | |
579 | ||
580 | /// Associated type for `<&[char] as Pattern<'a>>::Searcher`. | |
581 | #[derive(Clone)] | |
582 | pub struct CharSliceSearcher<'a, 'b>(<CharEqPattern<&'b [char]> as Pattern<'a>>::Searcher); | |
c34b1796 AL |
583 | |
584 | unsafe impl<'a, 'b> Searcher<'a> for CharSliceSearcher<'a, 'b> { | |
9346a6ac | 585 | searcher_methods!(forward); |
c34b1796 | 586 | } |
9346a6ac | 587 | |
c34b1796 | 588 | unsafe impl<'a, 'b> ReverseSearcher<'a> for CharSliceSearcher<'a, 'b> { |
9346a6ac | 589 | searcher_methods!(reverse); |
c34b1796 | 590 | } |
c34b1796 | 591 | |
9346a6ac | 592 | impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {} |
c34b1796 | 593 | |
9346a6ac AL |
594 | /// Searches for chars that are equal to any of the chars in the array |
595 | impl<'a, 'b> Pattern<'a> for &'b [char] { | |
596 | pattern_methods!(CharSliceSearcher<'a, 'b>, CharEqPattern, CharSliceSearcher); | |
c34b1796 AL |
597 | } |
598 | ||
9346a6ac AL |
599 | ///////////////////////////////////////////////////////////////////////////// |
600 | // Impl for F: FnMut(char) -> bool | |
601 | ///////////////////////////////////////////////////////////////////////////// | |
602 | ||
603 | /// Associated type for `<F as Pattern<'a>>::Searcher`. | |
604 | #[derive(Clone)] | |
605 | pub struct CharPredicateSearcher<'a, F>(<CharEqPattern<F> as Pattern<'a>>::Searcher) | |
606 | where F: FnMut(char) -> bool; | |
c34b1796 | 607 | |
9346a6ac | 608 | unsafe impl<'a, F> Searcher<'a> for CharPredicateSearcher<'a, F> |
c34b1796 AL |
609 | where F: FnMut(char) -> bool |
610 | { | |
9346a6ac | 611 | searcher_methods!(forward); |
c34b1796 | 612 | } |
9346a6ac AL |
613 | |
614 | unsafe impl<'a, F> ReverseSearcher<'a> for CharPredicateSearcher<'a, F> | |
c34b1796 AL |
615 | where F: FnMut(char) -> bool |
616 | { | |
9346a6ac | 617 | searcher_methods!(reverse); |
c34b1796 | 618 | } |
c34b1796 | 619 | |
9346a6ac AL |
620 | impl<'a, F> DoubleEndedSearcher<'a> for CharPredicateSearcher<'a, F> |
621 | where F: FnMut(char) -> bool {} | |
c34b1796 | 622 | |
9346a6ac AL |
623 | /// Searches for chars that match the given predicate |
624 | impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool { | |
625 | pattern_methods!(CharPredicateSearcher<'a, F>, CharEqPattern, CharPredicateSearcher); | |
626 | } | |
627 | ||
628 | ///////////////////////////////////////////////////////////////////////////// | |
629 | // Impl for &&str | |
630 | ///////////////////////////////////////////////////////////////////////////// | |
631 | ||
632 | /// Delegates to the `&str` impl. | |
c34b1796 | 633 | impl<'a, 'b> Pattern<'a> for &'b &'b str { |
9346a6ac | 634 | pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s); |
c34b1796 | 635 | } |