Skip to content

Commit c1de0a0

Browse files
committed
Added a Pattern impl that delegates to the dereference of a type.
This allows to match with a `&String` or `&&str`, for example.
1 parent ee930b0 commit c1de0a0

File tree

3 files changed

+99
-22
lines changed

3 files changed

+99
-22
lines changed

src/libcore/str/mod.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ macro_rules! delegate_iter {
7575
};
7676
(pattern $te:ty : $ti:ty) => {
7777
#[stable(feature = "rust1", since = "1.0.0")]
78-
impl<'a, P: CharEq> Iterator for $ti {
78+
impl<'a, P: Pattern<'a>> Iterator for $ti {
7979
type Item = $te;
8080

8181
#[inline]
@@ -88,7 +88,8 @@ macro_rules! delegate_iter {
8888
}
8989
}
9090
#[stable(feature = "rust1", since = "1.0.0")]
91-
impl<'a, P: CharEq> DoubleEndedIterator for $ti {
91+
impl<'a, P: Pattern<'a>> DoubleEndedIterator for $ti
92+
where P::Searcher: DoubleEndedSearcher<'a> {
9293
#[inline]
9394
fn next_back(&mut self) -> Option<$te> {
9495
self.0.next_back()
@@ -97,7 +98,8 @@ macro_rules! delegate_iter {
9798
};
9899
(pattern forward $te:ty : $ti:ty) => {
99100
#[stable(feature = "rust1", since = "1.0.0")]
100-
impl<'a, P: CharEq> Iterator for $ti {
101+
impl<'a, P: Pattern<'a>> Iterator for $ti
102+
where P::Searcher: DoubleEndedSearcher<'a> {
101103
type Item = $te;
102104

103105
#[inline]
@@ -610,7 +612,8 @@ where P::Searcher: DoubleEndedSearcher<'a> {
610612
}
611613

612614
#[stable(feature = "rust1", since = "1.0.0")]
613-
impl<'a, Sep: CharEq> Iterator for CharSplitsN<'a, Sep> {
615+
impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P>
616+
where P::Searcher: DoubleEndedSearcher<'a> {
614617
type Item = &'a str;
615618

616619
#[inline]
@@ -1379,7 +1382,7 @@ impl StrExt for str {
13791382
Split(CharSplits {
13801383
start: 0,
13811384
end: self.len(),
1382-
matcher: pat.into_matcher(self),
1385+
matcher: pat.into_searcher(self),
13831386
allow_trailing_empty: true,
13841387
finished: false,
13851388
})
@@ -1413,7 +1416,7 @@ impl StrExt for str {
14131416

14141417
#[inline]
14151418
fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
1416-
MatchIndices(pat.into_matcher(self))
1419+
MatchIndices(pat.into_searcher(self))
14171420
}
14181421

14191422
#[inline]
@@ -1487,7 +1490,7 @@ impl StrExt for str {
14871490
where P::Searcher: DoubleEndedSearcher<'a> {
14881491
let mut i = 0;
14891492
let mut j = self.len();
1490-
let mut matcher = pat.into_matcher(self);
1493+
let mut matcher = pat.into_searcher(self);
14911494
if let Some((a, b)) = matcher.next_reject() {
14921495
i = a;
14931496
j = b; // Rember earliest known match, correct it below if
@@ -1505,7 +1508,7 @@ impl StrExt for str {
15051508
#[inline]
15061509
fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
15071510
let mut i = 0;
1508-
let mut matcher = pat.into_matcher(self);
1511+
let mut matcher = pat.into_searcher(self);
15091512
if let Some((a, _)) = matcher.next_reject() {
15101513
i = a;
15111514
}
@@ -1519,7 +1522,7 @@ impl StrExt for str {
15191522
fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
15201523
where P::Searcher: ReverseSearcher<'a> {
15211524
let mut j = self.len();
1522-
let mut matcher = pat.into_matcher(self);
1525+
let mut matcher = pat.into_searcher(self);
15231526
if let Some((_, b)) = matcher.next_reject_back() {
15241527
j = b;
15251528
}
@@ -1591,12 +1594,12 @@ impl StrExt for str {
15911594
}
15921595

15931596
fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
1594-
pat.into_matcher(self).next_match().map(|(i, _)| i)
1597+
pat.into_searcher(self).next_match().map(|(i, _)| i)
15951598
}
15961599

15971600
fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
15981601
where P::Searcher: ReverseSearcher<'a> {
1599-
pat.into_matcher(self).next_match_back().map(|(i, _)| i)
1602+
pat.into_searcher(self).next_match_back().map(|(i, _)| i)
16001603
}
16011604

16021605
fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {

src/libcore/str/pattern.rs

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ use super::CharEq;
1717

1818
pub trait Pattern<'a>: Sized {
1919
type Searcher: Searcher<'a>;
20-
fn into_matcher(self, haystack: &'a str) -> Self::Searcher;
20+
fn into_searcher(self, haystack: &'a str) -> Self::Searcher;
2121

2222
#[inline]
2323
fn is_contained_in(self, haystack: &'a str) -> bool {
24-
self.into_matcher(haystack).next_match().is_some()
24+
self.into_searcher(haystack).next_match().is_some()
2525
}
2626

2727
#[inline]
2828
fn match_starts_at(self, haystack: &'a str, idx: usize) -> bool {
29-
let mut matcher = self.into_matcher(haystack);
29+
let mut matcher = self.into_searcher(haystack);
3030
loop {
3131
match matcher.next() {
3232
SearchStep::Match(i, _) if i == idx => return true,
@@ -42,7 +42,7 @@ pub trait Pattern<'a>: Sized {
4242
#[inline]
4343
fn match_ends_at(self, haystack: &'a str, idx: usize) -> bool
4444
where Self::Searcher: ReverseSearcher<'a> {
45-
let mut matcher = self.into_matcher(haystack);
45+
let mut matcher = self.into_searcher(haystack);
4646
loop {
4747
match matcher.next_back() {
4848
SearchStep::Match(_, j) if idx == j => return true,
@@ -115,25 +115,27 @@ pub unsafe trait ReverseSearcher<'a>: Searcher<'a> {
115115

116116
pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {}
117117

118-
// Impl for CharEq
118+
// Impl for a CharEq wrapper
119119

120-
pub struct CharEqSearcher<'a, C> {
120+
struct CharEqPattern<C: CharEq>(C);
121+
122+
pub struct CharEqSearcher<'a, C: CharEq> {
121123
char_eq: C,
122124
haystack: &'a str,
123125
char_indices: super::CharIndices<'a>,
124126
#[allow(dead_code)]
125127
ascii_only: bool,
126128
}
127129

128-
impl<'a, C: CharEq> Pattern<'a> for C {
130+
impl<'a, C: CharEq> Pattern<'a> for CharEqPattern<C> {
129131
type Searcher = CharEqSearcher<'a, C>;
130132

131133
#[inline]
132-
fn into_matcher(self, haystack: &'a str) -> CharEqSearcher<'a, C> {
134+
fn into_searcher(self, haystack: &'a str) -> CharEqSearcher<'a, C> {
133135
CharEqSearcher {
134-
ascii_only: self.only_ascii(),
136+
ascii_only: self.0.only_ascii(),
135137
haystack: haystack,
136-
char_eq: self,
138+
char_eq: self.0,
137139
char_indices: haystack.char_indices(),
138140
}
139141
}
@@ -203,7 +205,7 @@ impl<'a, 'b> Pattern<'a> for &'b str {
203205
type Searcher = StrSearcher<'a, 'b>;
204206

205207
#[inline]
206-
fn into_matcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> {
208+
fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> {
207209
StrSearcher {
208210
haystack: haystack,
209211
needle: self,
@@ -293,3 +295,65 @@ where F: FnOnce(&mut StrSearcher) -> SearchStep,
293295
SearchStep::Done
294296
}
295297
}
298+
299+
macro_rules! associated_items {
300+
($t:ty, $s:ident, $e:expr) => {
301+
// FIXME: #22463
302+
//type Searcher = $t;
303+
304+
fn into_searcher(self, haystack: &'a str) -> $t {
305+
let $s = self;
306+
$e.into_searcher(haystack)
307+
}
308+
309+
#[inline]
310+
fn is_contained_in(self, haystack: &'a str) -> bool {
311+
let $s = self;
312+
$e.is_contained_in(haystack)
313+
}
314+
315+
#[inline]
316+
fn match_starts_at(self, haystack: &'a str, idx: usize) -> bool {
317+
let $s = self;
318+
$e.match_starts_at(haystack, idx)
319+
}
320+
321+
// FIXME: #21750
322+
/*#[inline]
323+
fn match_ends_at(self, haystack: &'a str, idx: usize) -> bool
324+
where $t: ReverseSearcher<'a> {
325+
let $s = self;
326+
$e.match_ends_at(haystack, idx)
327+
}*/
328+
}
329+
}
330+
331+
// CharEq delegation impls
332+
333+
impl<'a, 'b> Pattern<'a> for &'b [char] {
334+
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
335+
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
336+
s, CharEqPattern(s));
337+
}
338+
339+
impl<'a> Pattern<'a> for char {
340+
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
341+
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
342+
s, CharEqPattern(s));
343+
}
344+
345+
impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool {
346+
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
347+
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
348+
s, CharEqPattern(s));
349+
}
350+
351+
// Deref-forward impl
352+
353+
use ops::Deref;
354+
355+
impl<'a, 'b, P: 'b + ?Sized, T: Deref<Target = P> + ?Sized> Pattern<'a> for &'b T where &'b P: Pattern<'a> {
356+
type Searcher = <&'b P as Pattern<'a>>::Searcher;
357+
associated_items!(<&'b P as Pattern<'a>>::Searcher,
358+
s, (&**s));
359+
}

src/libcoretest/str.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#[test]
12+
fn test_pattern_deref_forward() {
13+
let data = "aabcdaa";
14+
assert!(data.contains("bcd"));
15+
assert!(data.contains(&"bcd"));
16+
assert!(data.contains(&&"bcd"));
17+
assert!(data.contains(&"bcd".to_string()));
18+
assert!(data.contains(&&"bcd".to_string()));
19+
}
20+
1121
#[test]
1222
fn test_empty_match_indices() {
1323
let data = "aä中!";

0 commit comments

Comments
 (0)