From d5f2d3b1773d70bf3d32b94ad2a2bf3125bf743e Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Thu, 24 Sep 2015 08:38:48 -0700
Subject: [PATCH] std: Update MatchIndices to return a subslice

This commit updates the `MatchIndices` and `RMatchIndices` iterators to follow
the same pattern as the `chars` and `char_indices` iterators. The `matches`
iterator currently yield `&str` elements, so the `MatchIndices` iterator now
yields the index of the match as well as the `&str` that matched (instead of
start/end indexes).

cc #27743
---
 src/libcollections/str.rs        | 72 +++++++++++++-------------------
 src/libcollectionstest/str.rs    |  4 +-
 src/libcore/str/mod.rs           | 14 ++++---
 src/librustc/session/mod.rs      |  4 +-
 src/test/run-pass/issue-14919.rs |  2 +-
 5 files changed, 44 insertions(+), 52 deletions(-)

diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index 2f74ab5026e..a3d38bdd1b3 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -1157,25 +1157,21 @@ impl str {
         core_str::StrExt::rmatches(self, pat)
     }
 
-    /// An iterator over the start and end indices of the disjoint matches
-    /// of a pattern within `self`.
+    /// An iterator over the disjoint matches of a pattern within `self` as well
+    /// as the index that the match starts at.
     ///
     /// For matches of `pat` within `self` that overlap, only the indices
-    /// corresponding to the first
-    /// match are returned.
+    /// corresponding to the first match are returned.
     ///
-    /// The pattern can be a simple `&str`, `char`, or a closure that
-    /// determines if a character matches.
-    /// Additional libraries might provide more complex patterns like
-    /// regular expressions.
+    /// The pattern can be a simple `&str`, `char`, or a closure that determines
+    /// if a character matches. Additional libraries might provide more complex
+    /// patterns like regular expressions.
     ///
     /// # Iterator behavior
     ///
     /// The returned iterator will be double ended if the pattern allows a
-    /// reverse search
-    /// and forward/reverse search yields the same elements. This is true for,
-    /// eg, `char` but not
-    /// for `&str`.
+    /// reverse search and forward/reverse search yields the same elements. This
+    /// is true for, eg, `char` but not for `&str`.
     ///
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, `rmatch_indices()` can be used.
@@ -1185,42 +1181,36 @@ impl str {
     /// ```
     /// #![feature(str_match_indices)]
     ///
-    /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect();
-    /// assert_eq!(v, [(0, 3), (6, 9), (12, 15)]);
+    /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect();
+    /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]);
     ///
-    /// let v: Vec<(usize, usize)> = "1abcabc2".match_indices("abc").collect();
-    /// assert_eq!(v, [(1, 4), (4, 7)]);
+    /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect();
+    /// assert_eq!(v, [(1, "abc"), (4, "abc")]);
     ///
-    /// let v: Vec<(usize, usize)> = "ababa".match_indices("aba").collect();
-    /// assert_eq!(v, [(0, 3)]); // only the first `aba`
+    /// let v: Vec<_> = "ababa".match_indices("aba").collect();
+    /// assert_eq!(v, [(0, "aba")]); // only the first `aba`
     /// ```
     #[unstable(feature = "str_match_indices",
                reason = "might have its iterator type changed",
                issue = "27743")]
-    // NB: Right now MatchIndices yields `(usize, usize)`, but it would
-    // be more consistent with `matches` and `char_indices` to return `(usize, &str)`
     pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
         core_str::StrExt::match_indices(self, pat)
     }
 
-    /// An iterator over the start and end indices of the disjoint matches of
-    /// a pattern within
-    /// `self`, yielded in reverse order.
+    /// An iterator over the disjoint matches of a pattern within `self`,
+    /// yielded in reverse order along with the index of the match.
     ///
     /// For matches of `pat` within `self` that overlap, only the indices
-    /// corresponding to the last
-    /// match are returned.
+    /// corresponding to the last match are returned.
     ///
-    /// The pattern can be a simple `&str`, `char`, or a closure that
-    /// determines if a character matches.
-    /// Additional libraries might provide more complex patterns like
-    /// regular expressions.
+    /// The pattern can be a simple `&str`, `char`, or a closure that determines
+    /// if a character matches. Additional libraries might provide more complex
+    /// patterns like regular expressions.
     ///
     /// # Iterator behavior
     ///
-    /// The returned iterator requires that the pattern supports a
-    /// reverse search,
-    /// and it will be double ended if a forward/reverse search yields
+    /// The returned iterator requires that the pattern supports a reverse
+    /// search, and it will be double ended if a forward/reverse search yields
     /// the same elements.
     ///
     /// For iterating from the front, `match_indices()` can be used.
@@ -1230,20 +1220,18 @@ impl str {
     /// ```
     /// #![feature(str_match_indices)]
     ///
-    /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
-    /// assert_eq!(v, [(12, 15), (6, 9), (0, 3)]);
+    /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
+    /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]);
     ///
-    /// let v: Vec<(usize, usize)> = "1abcabc2".rmatch_indices("abc").collect();
-    /// assert_eq!(v, [(4, 7), (1, 4)]);
+    /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect();
+    /// assert_eq!(v, [(4, "abc"), (1, "abc")]);
     ///
-    /// let v: Vec<(usize, usize)> = "ababa".rmatch_indices("aba").collect();
-    /// assert_eq!(v, [(2, 5)]); // only the last `aba`
+    /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect();
+    /// assert_eq!(v, [(2, "aba")]); // only the last `aba`
     /// ```
     #[unstable(feature = "str_match_indices",
                reason = "might have its iterator type changed",
                issue = "27743")]
-    // NB: Right now RMatchIndices yields `(usize, usize)`, but it would
-    // be more consistent with `rmatches` and `char_indices` to return `(usize, &str)`
     pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
@@ -1416,10 +1404,10 @@ impl str {
     pub fn replace(&self, from: &str, to: &str) -> String {
         let mut result = String::new();
         let mut last_end = 0;
-        for (start, end) in self.match_indices(from) {
+        for (start, part) in self.match_indices(from) {
             result.push_str(unsafe { self.slice_unchecked(last_end, start) });
             result.push_str(to);
-            last_end = end;
+            last_end = start + part.len();
         }
         result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) });
         result
diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs
index 7b481f63991..b4555679e9c 100644
--- a/src/libcollectionstest/str.rs
+++ b/src/libcollectionstest/str.rs
@@ -1047,7 +1047,7 @@ fn test_pattern_deref_forward() {
 fn test_empty_match_indices() {
     let data = "aä中!";
     let vec: Vec<_> = data.match_indices("").collect();
-    assert_eq!(vec, [(0, 0), (1, 1), (3, 3), (6, 6), (7, 7)]);
+    assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]);
 }
 
 #[test]
@@ -1477,7 +1477,7 @@ generate_iterator_test! {
 
 generate_iterator_test! {
     double_ended_match_indices {
-        ("a1b2c3", char::is_numeric) -> [(1, 2), (3, 4), (5, 6)];
+        ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")];
     }
     with str::match_indices, str::rmatch_indices;
 }
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 69ebcb1ab7e..affa8918884 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -729,15 +729,19 @@ struct MatchIndicesInternal<'a, P: Pattern<'a>>(P::Searcher);
 
 impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
     #[inline]
-    fn next(&mut self) -> Option<(usize, usize)> {
-        self.0.next_match()
+    fn next(&mut self) -> Option<(usize, &'a str)> {
+        self.0.next_match().map(|(start, end)| unsafe {
+            (start, self.0.haystack().slice_unchecked(start, end))
+        })
     }
 
     #[inline]
-    fn next_back(&mut self) -> Option<(usize, usize)>
+    fn next_back(&mut self) -> Option<(usize, &'a str)>
         where P::Searcher: ReverseSearcher<'a>
     {
-        self.0.next_match_back()
+        self.0.next_match_back().map(|(start, end)| unsafe {
+            (start, self.0.haystack().slice_unchecked(start, end))
+        })
     }
 }
 
@@ -753,7 +757,7 @@ generate_pattern_iterators! {
                    reason = "type may be removed or have its iterator impl changed",
                    issue = "27743")]
     internal:
-        MatchIndicesInternal yielding ((usize, usize));
+        MatchIndicesInternal yielding ((usize, &'a str));
     delegate double ended;
 }
 
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index ff732ee7b9d..9d1674b74d1 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -331,10 +331,10 @@ fn split_msg_into_multilines(msg: &str) -> Option<String> {
     let first = msg.match_indices("expected").filter(|s| {
         s.0 > 0 && (msg.char_at_reverse(s.0) == ' ' ||
                     msg.char_at_reverse(s.0) == '(')
-    }).map(|(a, b)| (a - 1, b));
+    }).map(|(a, b)| (a - 1, a + b.len()));
     let second = msg.match_indices("found").filter(|s| {
         msg.char_at_reverse(s.0) == ' '
-    }).map(|(a, b)| (a - 1, b));
+    }).map(|(a, b)| (a - 1, a + b.len()));
 
     let mut new_msg = String::new();
     let mut head = 0;
diff --git a/src/test/run-pass/issue-14919.rs b/src/test/run-pass/issue-14919.rs
index 371e926ab18..d3c9fe9161c 100644
--- a/src/test/run-pass/issue-14919.rs
+++ b/src/test/run-pass/issue-14919.rs
@@ -59,5 +59,5 @@ fn match_indices<'a, M, T: IntoMatcher<'a, M>>(s: &'a str, from: T) -> MatchIndi
 fn main() {
     let s = "abcbdef";
     match_indices(s, |c: char| c == 'b')
-        .collect::<Vec<(usize, usize)>>();
+        .collect::<Vec<_>>();
 }