diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index bdb3b854fe2c0..a93083020334e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -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] @@ -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() @@ -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] @@ -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] @@ -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, }) @@ -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] @@ -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 @@ -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; } @@ -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; } @@ -1591,12 +1594,12 @@ impl StrExt for str { } fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - 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 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 { diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 2b77d877cf4fd..501fc27b37626 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -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, @@ -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, @@ -115,9 +115,11 @@ 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); + +pub struct CharEqSearcher<'a, C: CharEq> { char_eq: C, haystack: &'a str, char_indices: super::CharIndices<'a>, @@ -125,15 +127,15 @@ pub struct CharEqSearcher<'a, C> { ascii_only: bool, } -impl<'a, C: CharEq> Pattern<'a> for C { +impl<'a, C: CharEq> Pattern<'a> for CharEqPattern { 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(), } } @@ -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, @@ -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 = as Pattern<'a>>::Searcher; + associated_items!( as Pattern<'a>>::Searcher, + s, CharEqPattern(s)); +} + +impl<'a> Pattern<'a> for char { + type Searcher = as Pattern<'a>>::Searcher; + associated_items!( as Pattern<'a>>::Searcher, + s, CharEqPattern(s)); +} + +impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool { + type Searcher = as Pattern<'a>>::Searcher; + associated_items!( as Pattern<'a>>::Searcher, + s, CharEqPattern(s)); +} + +// Deref-forward impl + +use ops::Deref; + +impl<'a, 'b, P: 'b + ?Sized, T: Deref + ?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)); +} diff --git a/src/libcoretest/str.rs b/src/libcoretest/str.rs index 9bd7cf9833e90..acd8cc42c7298 100644 --- a/src/libcoretest/str.rs +++ b/src/libcoretest/str.rs @@ -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ä中!";