Skip to content

Commit

Permalink
Added a Pattern impl that delegates to the dereference of a type.
Browse files Browse the repository at this point in the history
This allows to match with a `&String` or `&&str`, for example.
  • Loading branch information
Kimundi committed Feb 19, 2015
1 parent ee930b0 commit c1de0a0
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 22 deletions.
25 changes: 14 additions & 11 deletions src/libcore/str/mod.rs
Expand Up @@ -75,7 +75,7 @@ macro_rules! delegate_iter {
};
(pattern $te:ty : $ti:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, P: CharEq> Iterator for $ti {
impl<'a, P: Pattern<'a>> Iterator for $ti {
type Item = $te;

#[inline]
Expand All @@ -88,7 +88,8 @@ macro_rules! delegate_iter {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, P: CharEq> DoubleEndedIterator for $ti {
impl<'a, P: Pattern<'a>> DoubleEndedIterator for $ti
where P::Searcher: DoubleEndedSearcher<'a> {
#[inline]
fn next_back(&mut self) -> Option<$te> {
self.0.next_back()
Expand All @@ -97,7 +98,8 @@ macro_rules! delegate_iter {
};
(pattern forward $te:ty : $ti:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, P: CharEq> Iterator for $ti {
impl<'a, P: Pattern<'a>> Iterator for $ti
where P::Searcher: DoubleEndedSearcher<'a> {
type Item = $te;

#[inline]
Expand Down Expand Up @@ -610,7 +612,8 @@ where P::Searcher: DoubleEndedSearcher<'a> {
}

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

#[inline]
Expand Down Expand Up @@ -1379,7 +1382,7 @@ impl StrExt for str {
Split(CharSplits {
start: 0,
end: self.len(),
matcher: pat.into_matcher(self),
matcher: pat.into_searcher(self),
allow_trailing_empty: true,
finished: false,
})
Expand Down Expand Up @@ -1413,7 +1416,7 @@ impl StrExt for str {

#[inline]
fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
MatchIndices(pat.into_matcher(self))
MatchIndices(pat.into_searcher(self))
}

#[inline]
Expand Down Expand Up @@ -1487,7 +1490,7 @@ impl StrExt for str {
where P::Searcher: DoubleEndedSearcher<'a> {
let mut i = 0;
let mut j = self.len();
let mut matcher = pat.into_matcher(self);
let mut matcher = pat.into_searcher(self);
if let Some((a, b)) = matcher.next_reject() {
i = a;
j = b; // Rember earliest known match, correct it below if
Expand All @@ -1505,7 +1508,7 @@ impl StrExt for str {
#[inline]
fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
let mut i = 0;
let mut matcher = pat.into_matcher(self);
let mut matcher = pat.into_searcher(self);
if let Some((a, _)) = matcher.next_reject() {
i = a;
}
Expand All @@ -1519,7 +1522,7 @@ impl StrExt for str {
fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
where P::Searcher: ReverseSearcher<'a> {
let mut j = self.len();
let mut matcher = pat.into_matcher(self);
let mut matcher = pat.into_searcher(self);
if let Some((_, b)) = matcher.next_reject_back() {
j = b;
}
Expand Down Expand Up @@ -1591,12 +1594,12 @@ impl StrExt for str {
}

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

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

fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
Expand Down
86 changes: 75 additions & 11 deletions src/libcore/str/pattern.rs
Expand Up @@ -17,16 +17,16 @@ use super::CharEq;

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

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

#[inline]
fn match_starts_at(self, haystack: &'a str, idx: usize) -> bool {
let mut matcher = self.into_matcher(haystack);
let mut matcher = self.into_searcher(haystack);
loop {
match matcher.next() {
SearchStep::Match(i, _) if i == idx => return true,
Expand All @@ -42,7 +42,7 @@ pub trait Pattern<'a>: Sized {
#[inline]
fn match_ends_at(self, haystack: &'a str, idx: usize) -> bool
where Self::Searcher: ReverseSearcher<'a> {
let mut matcher = self.into_matcher(haystack);
let mut matcher = self.into_searcher(haystack);
loop {
match matcher.next_back() {
SearchStep::Match(_, j) if idx == j => return true,
Expand Down Expand Up @@ -115,25 +115,27 @@ pub unsafe trait ReverseSearcher<'a>: Searcher<'a> {

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

// Impl for CharEq
// Impl for a CharEq wrapper

pub struct CharEqSearcher<'a, C> {
struct CharEqPattern<C: CharEq>(C);

pub struct CharEqSearcher<'a, C: CharEq> {
char_eq: C,
haystack: &'a str,
char_indices: super::CharIndices<'a>,
#[allow(dead_code)]
ascii_only: bool,
}

impl<'a, C: CharEq> Pattern<'a> for C {
impl<'a, C: CharEq> Pattern<'a> for CharEqPattern<C> {
type Searcher = CharEqSearcher<'a, C>;

#[inline]
fn into_matcher(self, haystack: &'a str) -> CharEqSearcher<'a, C> {
fn into_searcher(self, haystack: &'a str) -> CharEqSearcher<'a, C> {
CharEqSearcher {
ascii_only: self.only_ascii(),
ascii_only: self.0.only_ascii(),
haystack: haystack,
char_eq: self,
char_eq: self.0,
char_indices: haystack.char_indices(),
}
}
Expand Down Expand Up @@ -203,7 +205,7 @@ impl<'a, 'b> Pattern<'a> for &'b str {
type Searcher = StrSearcher<'a, 'b>;

#[inline]
fn into_matcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> {
fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> {
StrSearcher {
haystack: haystack,
needle: self,
Expand Down Expand Up @@ -293,3 +295,65 @@ where F: FnOnce(&mut StrSearcher) -> SearchStep,
SearchStep::Done
}
}

macro_rules! associated_items {
($t:ty, $s:ident, $e:expr) => {
// FIXME: #22463
//type Searcher = $t;

fn into_searcher(self, haystack: &'a str) -> $t {
let $s = self;
$e.into_searcher(haystack)
}

#[inline]
fn is_contained_in(self, haystack: &'a str) -> bool {
let $s = self;
$e.is_contained_in(haystack)
}

#[inline]
fn match_starts_at(self, haystack: &'a str, idx: usize) -> bool {
let $s = self;
$e.match_starts_at(haystack, idx)
}

// FIXME: #21750
/*#[inline]
fn match_ends_at(self, haystack: &'a str, idx: usize) -> bool
where $t: ReverseSearcher<'a> {
let $s = self;
$e.match_ends_at(haystack, idx)
}*/
}
}

// CharEq delegation impls

impl<'a, 'b> Pattern<'a> for &'b [char] {
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
s, CharEqPattern(s));
}

impl<'a> Pattern<'a> for char {
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
s, CharEqPattern(s));
}

impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool {
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
s, CharEqPattern(s));
}

// Deref-forward impl

use ops::Deref;

impl<'a, 'b, P: 'b + ?Sized, T: Deref<Target = P> + ?Sized> Pattern<'a> for &'b T where &'b P: Pattern<'a> {
type Searcher = <&'b P as Pattern<'a>>::Searcher;
associated_items!(<&'b P as Pattern<'a>>::Searcher,
s, (&**s));
}
10 changes: 10 additions & 0 deletions src/libcoretest/str.rs
Expand Up @@ -8,6 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[test]
fn test_pattern_deref_forward() {
let data = "aabcdaa";
assert!(data.contains("bcd"));
assert!(data.contains(&"bcd"));
assert!(data.contains(&&"bcd"));
assert!(data.contains(&"bcd".to_string()));
assert!(data.contains(&&"bcd".to_string()));
}

#[test]
fn test_empty_match_indices() {
let data = "aä中!";
Expand Down

0 comments on commit c1de0a0

Please sign in to comment.