about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarvin Löbel <loebel.marvin@gmail.com>2014-12-18 02:12:53 +0100
committerMarvin Löbel <loebel.marvin@gmail.com>2014-12-25 17:08:29 +0100
commit72c8f3772bdca40ff2be2908aaf6b6a73d1c7821 (patch)
tree4d3fd31002e58baeaf1be614a08cf2ef9a30733a
parentead198c5133fd649d1e385cfc46f344a2baaef8b (diff)
downloadrust-72c8f3772bdca40ff2be2908aaf6b6a73d1c7821.tar.gz
rust-72c8f3772bdca40ff2be2908aaf6b6a73d1c7821.zip
Prepared most `StrExt` pattern using methods for stabilization
Made iterator-returning methods return newtypes
Adjusted some docs to be forwards compatible with a generic pattern API
-rw-r--r--src/libcollections/str.rs179
-rw-r--r--src/libcore/str/mod.rs (renamed from src/libcore/str.rs)248
-rw-r--r--src/librustc/lint/builtin.rs6
-rw-r--r--src/libstd/path/windows.rs4
-rw-r--r--src/libunicode/u_str.rs9
5 files changed, 274 insertions, 172 deletions
diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index 5feae5e558e..446438c119f 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -80,12 +80,14 @@ use vec::Vec;
 
 pub use core::str::{from_utf8, CharEq, Chars, CharIndices};
 pub use core::str::{Bytes, CharSplits, is_utf8};
-pub use core::str::{CharSplitsN, Lines, LinesAny, MatchIndices, StrSplits};
+pub use core::str::{CharSplitsN, Lines, LinesAny, MatchIndices, StrSplits, SplitStr};
 pub use core::str::{CharRange};
 pub use core::str::{FromStr, from_str, Utf8Error};
 pub use core::str::Str;
 pub use core::str::{from_utf8_unchecked, from_c_str};
 pub use unicode::str::{Words, Graphemes, GraphemeIndices};
+pub use core::str::{Split, SplitTerminator};
+pub use core::str::{SplitN, RSplitN};
 
 // FIXME(conventions): ensure bit/char conventions are followed by str's API
 
@@ -721,7 +723,7 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// // not found, so no change.
     /// assert_eq!(s.replace("cookie monster", "little lamb"), s);
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
+    #[stable]
     fn replace(&self, from: &str, to: &str) -> String {
         let mut result = String::new();
         let mut last_end = 0;
@@ -828,36 +830,36 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
         }
     }
 
-    /// Returns true if one string contains another
+    /// Returns true if a string contains a string pattern.
     ///
     /// # Arguments
     ///
-    /// - needle - The string to look for
+    /// - pat - The string pattern to look for
     ///
     /// # Example
     ///
     /// ```rust
     /// assert!("bananas".contains("nana"));
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn contains(&self, needle: &str) -> bool {
-        core_str::StrExt::contains(self[], needle)
+    #[stable]
+    fn contains(&self, pat: &str) -> bool {
+        core_str::StrExt::contains(self[], pat)
     }
 
-    /// Returns true if a string contains a char.
+    /// Returns true if a string contains a char pattern.
     ///
     /// # Arguments
     ///
-    /// - needle - The char to look for
+    /// - pat - The char pattern to look for
     ///
     /// # Example
     ///
     /// ```rust
     /// assert!("hello".contains_char('e'));
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn contains_char(&self, needle: char) -> bool {
-        core_str::StrExt::contains_char(self[], needle)
+    #[unstable = "might get removed in favour of a more generic contains()"]
+    fn contains_char<P: CharEq>(&self, pat: P) -> bool {
+        core_str::StrExt::contains_char(self[], pat)
     }
 
     /// An iterator over the characters of `self`. Note, this iterates
@@ -894,7 +896,7 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     }
 
     /// An iterator over substrings of `self`, separated by characters
-    /// matched by `sep`.
+    /// matched by the pattern `pat`.
     ///
     /// # Example
     ///
@@ -911,13 +913,13 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// let v: Vec<&str> = "".split('X').collect();
     /// assert_eq!(v, vec![""]);
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn split<Sep: CharEq>(&self, sep: Sep) -> CharSplits<Sep> {
-        core_str::StrExt::split(self[], sep)
+    #[stable]
+    fn split<P: CharEq>(&self, pat: P) -> Split<P> {
+        core_str::StrExt::split(self[], pat)
     }
 
     /// An iterator over substrings of `self`, separated by characters
-    /// matched by `sep`, restricted to splitting at most `count`
+    /// matched by the pattern `pat`, restricted to splitting at most `count`
     /// times.
     ///
     /// # Example
@@ -938,13 +940,13 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// let v: Vec<&str> = "".splitn(1, 'X').collect();
     /// assert_eq!(v, vec![""]);
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn splitn<Sep: CharEq>(&self, count: uint, sep: Sep) -> CharSplitsN<Sep> {
-        core_str::StrExt::splitn(self[], count, sep)
+    #[stable]
+    fn splitn<P: CharEq>(&self, count: uint, pat: P) -> SplitN<P> {
+        core_str::StrExt::splitn(self[], count, pat)
     }
 
     /// An iterator over substrings of `self`, separated by characters
-    /// matched by `sep`.
+    /// matched by the pattern `pat`.
     ///
     /// Equivalent to `split`, except that the trailing substring
     /// is skipped if empty (terminator semantics).
@@ -967,13 +969,13 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').rev().collect();
     /// assert_eq!(v, vec!["leopard", "tiger", "", "lion"]);
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn split_terminator<Sep: CharEq>(&self, sep: Sep) -> CharSplits<Sep> {
-        core_str::StrExt::split_terminator(self[], sep)
+    #[unstable = "might get removed"]
+    fn split_terminator<P: CharEq>(&self, pat: P) -> SplitTerminator<P> {
+        core_str::StrExt::split_terminator(self[], pat)
     }
 
     /// An iterator over substrings of `self`, separated by characters
-    /// matched by `sep`, starting from the end of the string.
+    /// matched by the pattern `pat`, starting from the end of the string.
     /// Restricted to splitting at most `count` times.
     ///
     /// # Example
@@ -988,13 +990,13 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(2, 'X').collect();
     /// assert_eq!(v, vec!["leopard", "tiger", "lionX"]);
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn rsplitn<Sep: CharEq>(&self, count: uint, sep: Sep) -> CharSplitsN<Sep> {
-        core_str::StrExt::rsplitn(self[], count, sep)
+    #[stable]
+    fn rsplitn<P: CharEq>(&self, count: uint, pat: P) -> RSplitN<P> {
+        core_str::StrExt::rsplitn(self[], count, pat)
     }
 
     /// An iterator over the start and end indices of the disjoint
-    /// matches of `sep` within `self`.
+    /// matches of the pattern `pat` within `self`.
     ///
     /// That is, each returned value `(start, end)` satisfies
     /// `self.slice(start, end) == sep`. For matches of `sep` within
@@ -1013,12 +1015,12 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// let v: Vec<(uint, uint)> = "ababa".match_indices("aba").collect();
     /// assert_eq!(v, vec![(0, 3)]); // only the first `aba`
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn match_indices<'a>(&'a self, sep: &'a str) -> MatchIndices<'a> {
-        core_str::StrExt::match_indices(self[], sep)
+    #[unstable = "might have its iterator type changed"]
+    fn match_indices<'a>(&'a self, pat: &'a str) -> MatchIndices<'a> {
+        core_str::StrExt::match_indices(self[], pat)
     }
 
-    /// An iterator over the substrings of `self` separated by `sep`.
+    /// An iterator over the substrings of `self` separated by the pattern `sep`.
     ///
     /// # Example
     ///
@@ -1029,9 +1031,9 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// let v: Vec<&str> = "1abcabc2".split_str("abc").collect();
     /// assert_eq!(v, vec!["1", "", "2"]);
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn split_str<'a>(&'a self, s: &'a str) -> StrSplits<'a> {
-        core_str::StrExt::split_str(self[], s)
+    #[unstable = "might get removed in the future in favor of a more generic split()"]
+    fn split_str<'a>(&'a self, pat: &'a str) -> StrSplits<'a> {
+        core_str::StrExt::split_str(self[], pat)
     }
 
     /// An iterator over the lines of a string (subsequences separated
@@ -1204,85 +1206,106 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
         core_str::StrExt::slice_unchecked(self[], begin, end)
     }
 
-    /// Returns true if `needle` is a prefix of the string.
+    /// Returns true if the pattern `pat` is a prefix of the string.
     ///
     /// # Example
     ///
     /// ```rust
     /// assert!("banana".starts_with("ba"));
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn starts_with(&self, needle: &str) -> bool {
-        core_str::StrExt::starts_with(self[], needle)
+    #[stable]
+    fn starts_with(&self, pat: &str) -> bool {
+        core_str::StrExt::starts_with(self[], pat)
     }
 
-    /// Returns true if `needle` is a suffix of the string.
+    /// Returns true if the pattern `pat` is a suffix of the string.
     ///
     /// # Example
     ///
     /// ```rust
     /// assert!("banana".ends_with("nana"));
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn ends_with(&self, needle: &str) -> bool {
-        core_str::StrExt::ends_with(self[], needle)
+    #[stable]
+    fn ends_with(&self, pat: &str) -> bool {
+        core_str::StrExt::ends_with(self[], pat)
     }
 
-    /// Returns a string with characters that match `to_trim` removed from the left and the right.
+    /// Returns a string with all pre- and suffixes that match
+    /// the pattern `pat` repeatedly removed.
     ///
     /// # Arguments
     ///
-    /// * to_trim - a character matcher
+    /// * pat - a string pattern
     ///
     /// # Example
     ///
     /// ```rust
-    /// assert_eq!("11foo1bar11".trim_chars('1'), "foo1bar");
+    /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
     /// let x: &[_] = &['1', '2'];
-    /// assert_eq!("12foo1bar12".trim_chars(x), "foo1bar");
-    /// assert_eq!("123foo1bar123".trim_chars(|&: c: char| c.is_numeric()), "foo1bar");
+    /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar");
+    /// assert_eq!("123foo1bar123".trim_matches(|&: c: char| c.is_numeric()), "foo1bar");
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn trim_chars<C: CharEq>(&self, to_trim: C) -> &str {
-        core_str::StrExt::trim_chars(self[], to_trim)
+    #[stable]
+    fn trim_matches<P: CharEq>(&self, pat: P) -> &str {
+        core_str::StrExt::trim_matches(self[], pat)
     }
 
-    /// Returns a string with leading `chars_to_trim` removed.
+    /// Deprecated
+    #[deprecated = "Replaced by `trim_matches`"]
+    fn trim_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str {
+        self.trim_matches(to_trim)
+    }
+
+    /// Returns a string with all prefixes that match
+    /// the pattern `pat` repeatedly removed.
     ///
     /// # Arguments
     ///
-    /// * to_trim - a character matcher
+    /// * pat - a string pattern
     ///
     /// # Example
     ///
     /// ```rust
-    /// assert_eq!("11foo1bar11".trim_left_chars('1'), "foo1bar11");
+    /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
     /// let x: &[_] = &['1', '2'];
-    /// assert_eq!("12foo1bar12".trim_left_chars(x), "foo1bar12");
-    /// assert_eq!("123foo1bar123".trim_left_chars(|&: c: char| c.is_numeric()), "foo1bar123");
+    /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
+    /// assert_eq!("123foo1bar123".trim_left_matches(|&: c: char| c.is_numeric()), "foo1bar123");
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn trim_left_chars<C: CharEq>(&self, to_trim: C) -> &str {
-        core_str::StrExt::trim_left_chars(self[], to_trim)
+    #[stable]
+    fn trim_left_matches<P: CharEq>(&self, pat: P) -> &str {
+        core_str::StrExt::trim_left_matches(self[], pat)
+    }
+
+    /// Deprecated
+    #[deprecated = "Replaced by `trim_left_matches`"]
+    fn trim_left_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str {
+        self.trim_left_matches(to_trim)
     }
 
-    /// Returns a string with trailing `chars_to_trim` removed.
+    /// Returns a string with all suffixes that match
+    /// the pattern `pat` repeatedly removed.
     ///
     /// # Arguments
     ///
-    /// * to_trim - a character matcher
+    /// * pat - a string pattern
     ///
     /// # Example
     ///
     /// ```rust
-    /// assert_eq!("11foo1bar11".trim_right_chars('1'), "11foo1bar");
+    /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
     /// let x: &[_] = &['1', '2'];
-    /// assert_eq!("12foo1bar12".trim_right_chars(x), "12foo1bar");
-    /// assert_eq!("123foo1bar123".trim_right_chars(|&: c: char| c.is_numeric()), "123foo1bar");
+    /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
+    /// assert_eq!("123foo1bar123".trim_right_matches(|&: c: char| c.is_numeric()), "123foo1bar");
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn trim_right_chars<C: CharEq>(&self, to_trim: C) -> &str {
-        core_str::StrExt::trim_right_chars(self[], to_trim)
+    #[stable]
+    fn trim_right_matches<P: CharEq>(&self, pat: P) -> &str {
+        core_str::StrExt::trim_right_matches(self[], pat)
+    }
+
+    /// Deprecated
+    #[deprecated = "Replaced by `trim_right_matches`"]
+    fn trim_right_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str {
+        self.trim_right_matches(to_trim)
     }
 
     /// Check that `index`-th byte lies at the start and/or end of a
@@ -1430,7 +1453,7 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     }
 
     /// Returns the byte index of the first character of `self` that
-    /// matches `search`.
+    /// matches the pattern `pat`.
     ///
     /// # Return value
     ///
@@ -1452,13 +1475,13 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// let x: &[_] = &['1', '2'];
     /// assert_eq!(s.find(x), None);
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn find<C: CharEq>(&self, search: C) -> Option<uint> {
-        core_str::StrExt::find(self[], search)
+    #[unstable = "might be superseded by match_indices"]
+    fn find<P: CharEq>(&self, pat: P) -> Option<uint> {
+        core_str::StrExt::find(self[], pat)
     }
 
     /// Returns the byte index of the last character of `self` that
-    /// matches `search`.
+    /// matches the pattern `pat`.
     ///
     /// # Return value
     ///
@@ -1480,9 +1503,9 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// let x: &[_] = &['1', '2'];
     /// assert_eq!(s.rfind(x), None);
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
-    fn rfind<C: CharEq>(&self, search: C) -> Option<uint> {
-        core_str::StrExt::rfind(self[], search)
+    #[unstable = "might be superseded by match_indices"]
+    fn rfind<P: CharEq>(&self, pat: P) -> Option<uint> {
+        core_str::StrExt::rfind(self[], pat)
     }
 
     /// Returns the byte index of the first matching substring
@@ -1504,7 +1527,7 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// assert_eq!(s.find_str("老虎 L"), Some(6));
     /// assert_eq!(s.find_str("muffin man"), None);
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
+    #[unstable = "might get removed in favor of a more generic find in the future"]
     fn find_str(&self, needle: &str) -> Option<uint> {
         core_str::StrExt::find_str(self[], needle)
     }
@@ -1546,7 +1569,7 @@ pub trait StrExt for Sized?: ops::Slice<uint, str> {
     /// assert!(string.subslice_offset(lines[1]) == 2); // &"b"
     /// assert!(string.subslice_offset(lines[2]) == 4); // &"c"
     /// ```
-    #[unstable = "awaiting pattern/matcher stabilization"]
+    #[unstable = "awaiting convention about comparability of arbitrary slices"]
     fn subslice_offset(&self, inner: &str) -> uint {
         core_str::StrExt::subslice_offset(self[], inner)
     }
diff --git a/src/libcore/str.rs b/src/libcore/str/mod.rs
index 204ffae6cbd..1e7fe8f060c 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str/mod.rs
@@ -18,7 +18,6 @@
 
 use self::Searcher::{Naive, TwoWay, TwoWayLong};
 
-use clone::Clone;
 use cmp::{mod, Eq};
 use default::Default;
 use iter::range;
@@ -35,6 +34,70 @@ use result::Result::{mod, Ok, Err};
 use slice::{mod, SliceExt};
 use uint;
 
+macro_rules! delegate_iter {
+    (exact $te:ty in $ti:ty) => {
+        delegate_iter!{$te in $ti}
+        impl<'a> ExactSizeIterator<$te> for $ti {
+            #[inline]
+            fn rposition<P>(&mut self, predicate: P) -> Option<uint> where P: FnMut($te) -> bool{
+                self.0.rposition(predicate)
+            }
+            #[inline]
+            fn len(&self) -> uint {
+                self.0.len()
+            }
+        }
+    };
+    ($te:ty in $ti:ty) => {
+        impl<'a> Iterator<$te> for $ti {
+            #[inline]
+            fn next(&mut self) -> Option<$te> {
+                self.0.next()
+            }
+            #[inline]
+            fn size_hint(&self) -> (uint, Option<uint>) {
+                self.0.size_hint()
+            }
+        }
+        impl<'a> DoubleEndedIterator<$te> for $ti {
+            #[inline]
+            fn next_back(&mut self) -> Option<$te> {
+                self.0.next_back()
+            }
+        }
+    };
+    (pattern $te:ty in $ti:ty) => {
+        impl<'a, P: CharEq> Iterator<$te> for $ti {
+            #[inline]
+            fn next(&mut self) -> Option<$te> {
+                self.0.next()
+            }
+            #[inline]
+            fn size_hint(&self) -> (uint, Option<uint>) {
+                self.0.size_hint()
+            }
+        }
+        impl<'a, P: CharEq> DoubleEndedIterator<$te> for $ti {
+            #[inline]
+            fn next_back(&mut self) -> Option<$te> {
+                self.0.next_back()
+            }
+        }
+    };
+    (pattern forward $te:ty in $ti:ty) => {
+        impl<'a, P: CharEq> Iterator<$te> for $ti {
+            #[inline]
+            fn next(&mut self) -> Option<$te> {
+                self.0.next()
+            }
+            #[inline]
+            fn size_hint(&self) -> (uint, Option<uint>) {
+                self.0.size_hint()
+            }
+        }
+    }
+}
+
 /// A trait to abstract the idea of creating a new instance of a type from a
 /// string.
 // FIXME(#17307): there should be an `E` associated type for a `Result` return
@@ -333,29 +396,28 @@ impl<'a> DoubleEndedIterator<(uint, char)> for CharIndices<'a> {
 
 /// External iterator for a string's bytes.
 /// Use with the `std::iter` module.
+///
+/// Created with `StrExt::bytes`
 #[stable]
 #[deriving(Clone)]
-pub struct Bytes<'a> {
-    inner: Map<&'a u8, u8, slice::Iter<'a, u8>, BytesFn>,
-}
+pub struct Bytes<'a>(Map<&'a u8, u8, slice::Iter<'a, u8>, BytesDeref>);
+delegate_iter!{exact u8 in Bytes<'a>}
 
-/// A temporary new type wrapper that ensures that the `Bytes` iterator
+/// A temporary fn new type that ensures that the `Bytes` iterator
 /// is cloneable.
-#[deriving(Copy)]
-struct BytesFn(fn(&u8) -> u8);
+#[deriving(Copy, Clone)]
+struct BytesDeref;
 
-impl<'a> Fn(&'a u8) -> u8 for BytesFn {
+impl<'a> Fn(&'a u8) -> u8 for BytesDeref {
+    #[inline]
     extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
-        (self.0)(ptr)
+        *ptr
     }
 }
 
-impl Clone for BytesFn {
-    fn clone(&self) -> BytesFn { *self }
-}
-
 /// An iterator over the substrings of a string, separated by `sep`.
 #[deriving(Clone)]
+#[deprecated = "Type is now named `Split` or `SplitTerminator`"]
 pub struct CharSplits<'a, Sep> {
     /// The slice remaining to be iterated
     string: &'a str,
@@ -369,6 +431,7 @@ pub struct CharSplits<'a, Sep> {
 /// An iterator over the substrings of a string, separated by `sep`,
 /// splitting at most `count` times.
 #[deriving(Clone)]
+#[deprecated = "Type is now named `SplitN` or `RSplitN`"]
 pub struct CharSplitsN<'a, Sep> {
     iter: CharSplits<'a, Sep>,
     /// The number of splits remaining
@@ -790,12 +853,17 @@ pub struct MatchIndices<'a> {
 /// An iterator over the substrings of a string separated by a given
 /// search string
 #[deriving(Clone)]
-pub struct StrSplits<'a> {
+#[unstable = "Type might get removed"]
+pub struct SplitStr<'a> {
     it: MatchIndices<'a>,
     last_end: uint,
     finished: bool
 }
 
+/// Deprecated
+#[deprecated = "Type is now named `SplitStr`"]
+pub type StrSplits<'a> = SplitStr<'a>;
+
 impl<'a> Iterator<(uint, uint)> for MatchIndices<'a> {
     #[inline]
     fn next(&mut self) -> Option<(uint, uint)> {
@@ -810,7 +878,7 @@ impl<'a> Iterator<(uint, uint)> for MatchIndices<'a> {
     }
 }
 
-impl<'a> Iterator<&'a str> for StrSplits<'a> {
+impl<'a> Iterator<&'a str> for SplitStr<'a> {
     #[inline]
     fn next(&mut self) -> Option<&'a str> {
         if self.finished { return None; }
@@ -1158,23 +1226,47 @@ impl<'a, Sized? S> Str for &'a S where S: Str {
     fn as_slice(&self) -> &str { Str::as_slice(*self) }
 }
 
+/// Return type of `StrExt::split`
+#[deriving(Clone)]
+#[stable]
+pub struct Split<'a, P>(CharSplits<'a, P>);
+delegate_iter!{pattern &'a str in Split<'a, P>}
+
+/// Return type of `StrExt::split_terminator`
+#[deriving(Clone)]
+#[unstable = "might get removed in favour of a constructor method on Split"]
+pub struct SplitTerminator<'a, P>(CharSplits<'a, P>);
+delegate_iter!{pattern &'a str in SplitTerminator<'a, P>}
+
+/// Return type of `StrExt::splitn`
+#[deriving(Clone)]
+#[stable]
+pub struct SplitN<'a, P>(CharSplitsN<'a, P>);
+delegate_iter!{pattern forward &'a str in SplitN<'a, P>}
+
+/// Return type of `StrExt::rsplitn`
+#[deriving(Clone)]
+#[stable]
+pub struct RSplitN<'a, P>(CharSplitsN<'a, P>);
+delegate_iter!{pattern forward &'a str in RSplitN<'a, P>}
+
 /// Methods for string slices
 #[allow(missing_docs)]
 pub trait StrExt for Sized? {
     // NB there are no docs here are they're all located on the StrExt trait in
     // libcollections, not here.
 
-    fn contains(&self, needle: &str) -> bool;
-    fn contains_char(&self, needle: char) -> bool;
+    fn contains(&self, pat: &str) -> bool;
+    fn contains_char<P: CharEq>(&self, pat: P) -> bool;
     fn chars<'a>(&'a self) -> Chars<'a>;
     fn bytes<'a>(&'a self) -> Bytes<'a>;
     fn char_indices<'a>(&'a self) -> CharIndices<'a>;
-    fn split<'a, Sep: CharEq>(&'a self, sep: Sep) -> CharSplits<'a, Sep>;
-    fn splitn<'a, Sep: CharEq>(&'a self, count: uint, sep: Sep) -> CharSplitsN<'a, Sep>;
-    fn split_terminator<'a, Sep: CharEq>(&'a self, sep: Sep) -> CharSplits<'a, Sep>;
-    fn rsplitn<'a, Sep: CharEq>(&'a self, count: uint, sep: Sep) -> CharSplitsN<'a, Sep>;
+    fn split<'a, P: CharEq>(&'a self, pat: P) -> Split<'a, P>;
+    fn splitn<'a, P: CharEq>(&'a self, count: uint, pat: P) -> SplitN<'a, P>;
+    fn split_terminator<'a, P: CharEq>(&'a self, pat: P) -> SplitTerminator<'a, P>;
+    fn rsplitn<'a, P: CharEq>(&'a self, count: uint, pat: P) -> RSplitN<'a, P>;
     fn match_indices<'a>(&'a self, sep: &'a str) -> MatchIndices<'a>;
-    fn split_str<'a>(&'a self, &'a str) -> StrSplits<'a>;
+    fn split_str<'a>(&'a self, pat: &'a str) -> SplitStr<'a>;
     fn lines<'a>(&'a self) -> Lines<'a>;
     fn lines_any<'a>(&'a self) -> LinesAny<'a>;
     fn char_len(&self) -> uint;
@@ -1183,20 +1275,20 @@ pub trait StrExt for Sized? {
     fn slice_to<'a>(&'a self, end: uint) -> &'a str;
     fn slice_chars<'a>(&'a self, begin: uint, end: uint) -> &'a str;
     unsafe fn slice_unchecked<'a>(&'a self, begin: uint, end: uint) -> &'a str;
-    fn starts_with(&self, needle: &str) -> bool;
-    fn ends_with(&self, needle: &str) -> bool;
-    fn trim_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str;
-    fn trim_left_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str;
-    fn trim_right_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str;
+    fn starts_with(&self, pat: &str) -> bool;
+    fn ends_with(&self, pat: &str) -> bool;
+    fn trim_matches<'a, P: CharEq>(&'a self, pat: P) -> &'a str;
+    fn trim_left_matches<'a, P: CharEq>(&'a self, pat: P) -> &'a str;
+    fn trim_right_matches<'a, P: CharEq>(&'a self, pat: P) -> &'a str;
     fn is_char_boundary(&self, index: uint) -> bool;
     fn char_range_at(&self, start: uint) -> CharRange;
     fn char_range_at_reverse(&self, start: uint) -> CharRange;
     fn char_at(&self, i: uint) -> char;
     fn char_at_reverse(&self, i: uint) -> char;
     fn as_bytes<'a>(&'a self) -> &'a [u8];
-    fn find<C: CharEq>(&self, search: C) -> Option<uint>;
-    fn rfind<C: CharEq>(&self, search: C) -> Option<uint>;
-    fn find_str(&self, &str) -> Option<uint>;
+    fn find<P: CharEq>(&self, pat: P) -> Option<uint>;
+    fn rfind<P: CharEq>(&self, pat: P) -> Option<uint>;
+    fn find_str(&self, pat: &str) -> Option<uint>;
     fn slice_shift_char<'a>(&'a self) -> Option<(char, &'a str)>;
     fn subslice_offset(&self, inner: &str) -> uint;
     fn as_ptr(&self) -> *const u8;
@@ -1218,8 +1310,8 @@ impl StrExt for str {
     }
 
     #[inline]
-    fn contains_char(&self, needle: char) -> bool {
-        self.find(needle).is_some()
+    fn contains_char<P: CharEq>(&self, pat: P) -> bool {
+        self.find(pat).is_some()
     }
 
     #[inline]
@@ -1229,9 +1321,7 @@ impl StrExt for str {
 
     #[inline]
     fn bytes(&self) -> Bytes {
-        fn deref(&x: &u8) -> u8 { x }
-
-        Bytes { inner: self.as_bytes().iter().map(BytesFn(deref)) }
+        Bytes(self.as_bytes().iter().map(BytesDeref))
     }
 
     #[inline]
@@ -1240,43 +1330,44 @@ impl StrExt for str {
     }
 
     #[inline]
-    fn split<Sep: CharEq>(&self, sep: Sep) -> CharSplits<Sep> {
-        CharSplits {
+    #[allow(deprecated)] // For using CharSplits
+    fn split<P: CharEq>(&self, pat: P) -> Split<P> {
+        Split(CharSplits {
             string: self,
-            only_ascii: sep.only_ascii(),
-            sep: sep,
+            only_ascii: pat.only_ascii(),
+            sep: pat,
             allow_trailing_empty: true,
             finished: false,
-        }
+        })
     }
 
     #[inline]
-    fn splitn<Sep: CharEq>(&self, count: uint, sep: Sep)
-        -> CharSplitsN<Sep> {
-        CharSplitsN {
-            iter: self.split(sep),
+    #[allow(deprecated)] // For using CharSplitsN
+    fn splitn<P: CharEq>(&self, count: uint, pat: P) -> SplitN<P> {
+        SplitN(CharSplitsN {
+            iter: self.split(pat).0,
             count: count,
             invert: false,
-        }
+        })
     }
 
     #[inline]
-    fn split_terminator<Sep: CharEq>(&self, sep: Sep)
-        -> CharSplits<Sep> {
-        CharSplits {
+    #[allow(deprecated)] // For using CharSplits
+    fn split_terminator<P: CharEq>(&self, pat: P) -> SplitTerminator<P> {
+        SplitTerminator(CharSplits {
             allow_trailing_empty: false,
-            ..self.split(sep)
-        }
+            ..self.split(pat).0
+        })
     }
 
     #[inline]
-    fn rsplitn<Sep: CharEq>(&self, count: uint, sep: Sep)
-        -> CharSplitsN<Sep> {
-        CharSplitsN {
-            iter: self.split(sep),
+    #[allow(deprecated)] // For using CharSplitsN
+    fn rsplitn<P: CharEq>(&self, count: uint, pat: P) -> RSplitN<P> {
+        RSplitN(CharSplitsN {
+            iter: self.split(pat).0,
             count: count,
             invert: true,
-        }
+        })
     }
 
     #[inline]
@@ -1290,8 +1381,8 @@ impl StrExt for str {
     }
 
     #[inline]
-    fn split_str<'a>(&'a self, sep: &'a str) -> StrSplits<'a> {
-        StrSplits {
+    fn split_str<'a>(&'a self, sep: &'a str) -> SplitStr<'a> {
+        SplitStr {
             it: self.match_indices(sep),
             last_end: 0,
             finished: false
@@ -1300,7 +1391,7 @@ impl StrExt for str {
 
     #[inline]
     fn lines(&self) -> Lines {
-        Lines { inner: self.split_terminator('\n') }
+        Lines { inner: self.split_terminator('\n').0 }
     }
 
     fn lines_any(&self) -> LinesAny {
@@ -1393,12 +1484,12 @@ impl StrExt for str {
     }
 
     #[inline]
-    fn trim_chars<C: CharEq>(&self, mut to_trim: C) -> &str {
-        let cur = match self.find(|&mut: c: char| !to_trim.matches(c)) {
+    fn trim_matches<P: CharEq>(&self, mut pat: P) -> &str {
+        let cur = match self.find(|&mut: c: char| !pat.matches(c)) {
             None => "",
             Some(i) => unsafe { self.slice_unchecked(i, self.len()) }
         };
-        match cur.rfind(|&mut: c: char| !to_trim.matches(c)) {
+        match cur.rfind(|&mut: c: char| !pat.matches(c)) {
             None => "",
             Some(i) => {
                 let right = cur.char_range_at(i).next;
@@ -1408,16 +1499,16 @@ impl StrExt for str {
     }
 
     #[inline]
-    fn trim_left_chars<C: CharEq>(&self, mut to_trim: C) -> &str {
-        match self.find(|&mut: c: char| !to_trim.matches(c)) {
+    fn trim_left_matches<P: CharEq>(&self, mut pat: P) -> &str {
+        match self.find(|&mut: c: char| !pat.matches(c)) {
             None => "",
             Some(first) => unsafe { self.slice_unchecked(first, self.len()) }
         }
     }
 
     #[inline]
-    fn trim_right_chars<C: CharEq>(&self, mut to_trim: C) -> &str {
-        match self.rfind(|&mut: c: char| !to_trim.matches(c)) {
+    fn trim_right_matches<P: CharEq>(&self, mut pat: P) -> &str {
+        match self.rfind(|&mut: c: char| !pat.matches(c)) {
             None => "",
             Some(last) => {
                 let next = self.char_range_at(last).next;
@@ -1504,23 +1595,23 @@ impl StrExt for str {
         unsafe { mem::transmute(self) }
     }
 
-    fn find<C: CharEq>(&self, mut search: C) -> Option<uint> {
-        if search.only_ascii() {
-            self.bytes().position(|b| search.matches(b as char))
+    fn find<P: CharEq>(&self, mut pat: P) -> Option<uint> {
+        if pat.only_ascii() {
+            self.bytes().position(|b| pat.matches(b as char))
         } else {
             for (index, c) in self.char_indices() {
-                if search.matches(c) { return Some(index); }
+                if pat.matches(c) { return Some(index); }
             }
             None
         }
     }
 
-    fn rfind<C: CharEq>(&self, mut search: C) -> Option<uint> {
-        if search.only_ascii() {
-            self.bytes().rposition(|b| search.matches(b as char))
+    fn rfind<P: CharEq>(&self, mut pat: P) -> Option<uint> {
+        if pat.only_ascii() {
+            self.bytes().rposition(|b| pat.matches(b as char))
         } else {
             for (index, c) in self.char_indices().rev() {
-                if search.matches(c) { return Some(index); }
+                if pat.matches(c) { return Some(index); }
             }
             None
         }
@@ -1596,14 +1687,3 @@ impl<'a> DoubleEndedIterator<&'a str> for LinesAny<'a> {
     #[inline]
     fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() }
 }
-impl<'a> Iterator<u8> for Bytes<'a> {
-    #[inline]
-    fn next(&mut self) -> Option<u8> { self.inner.next() }
-    #[inline]
-    fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
-}
-impl<'a> DoubleEndedIterator<u8> for Bytes<'a> {
-    #[inline]
-    fn next_back(&mut self) -> Option<u8> { self.inner.next_back() }
-}
-impl<'a> ExactSizeIterator<u8> for Bytes<'a> {}
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 0fd69ea25bc..1d998567b6e 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -817,7 +817,7 @@ impl NonCamelCaseTypes {
         fn is_camel_case(ident: ast::Ident) -> bool {
             let ident = token::get_ident(ident);
             if ident.get().is_empty() { return true; }
-            let ident = ident.get().trim_chars('_');
+            let ident = ident.get().trim_matches('_');
 
             // start with a non-lowercase letter rather than non-uppercase
             // ones (some scripts don't have a concept of upper/lowercase)
@@ -940,8 +940,8 @@ impl NonSnakeCase {
         fn is_snake_case(ident: ast::Ident) -> bool {
             let ident = token::get_ident(ident);
             if ident.get().is_empty() { return true; }
-            let ident = ident.get().trim_left_chars('\'');
-            let ident = ident.trim_chars('_');
+            let ident = ident.get().trim_left_matches('\'');
+            let ident = ident.trim_matches('_');
 
             let mut allow_underscore = true;
             ident.chars().all(|c| {
diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs
index 7d10188c437..4cb2e496d92 100644
--- a/src/libstd/path/windows.rs
+++ b/src/libstd/path/windows.rs
@@ -26,7 +26,7 @@ use mem;
 use option::Option;
 use option::Option::{Some, None};
 use slice::SliceExt;
-use str::{CharSplits, FromStr, StrVector, StrExt};
+use str::{SplitTerminator, FromStr, StrVector, StrExt};
 use string::{String, ToString};
 use unicode::char::UnicodeChar;
 use vec::Vec;
@@ -38,7 +38,7 @@ use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe};
 /// Each component is yielded as Option<&str> for compatibility with PosixPath, but
 /// every component in WindowsPath is guaranteed to be Some.
 pub type StrComponents<'a> =
-    Map<&'a str, Option<&'a str>, CharSplits<'a, char>, fn(&'a str) -> Option<&'a str>>;
+    Map<&'a str, Option<&'a str>, SplitTerminator<'a, char>, fn(&'a str) -> Option<&'a str>>;
 
 /// Iterator that yields successive components of a Path as &[u8]
 pub type Components<'a> =
diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs
index a3d4dd057d0..3b0cc1443f0 100644
--- a/src/libunicode/u_str.rs
+++ b/src/libunicode/u_str.rs
@@ -24,16 +24,15 @@ use core::iter::{Filter, AdditiveIterator};
 use core::mem;
 use core::num::Int;
 use core::slice;
-use core::str::CharSplits;
+use core::str::Split;
 
 use u_char::UnicodeChar;
 use tables::grapheme::GraphemeCat;
 
 /// An iterator over the words of a string, separated by a sequence of whitespace
-/// FIXME: This should be opaque
 #[stable]
 pub struct Words<'a> {
-    inner: Filter<&'a str, CharSplits<'a, fn(char) -> bool>, fn(&&str) -> bool>,
+    inner: Filter<&'a str, Split<'a, fn(char) -> bool>, fn(&&str) -> bool>,
 }
 
 /// Methods for Unicode string slices
@@ -90,12 +89,12 @@ impl UnicodeStr for str {
 
     #[inline]
     fn trim_left(&self) -> &str {
-        self.trim_left_chars(|&: c: char| c.is_whitespace())
+        self.trim_left_matches(|&: c: char| c.is_whitespace())
     }
 
     #[inline]
     fn trim_right(&self) -> &str {
-        self.trim_right_chars(|&: c: char| c.is_whitespace())
+        self.trim_right_matches(|&: c: char| c.is_whitespace())
     }
 }