auto merge of #20058 : Kimundi/rust/str_pattern_pre, r=alexcrichton

This stabilizes most methods on `&str` working with patterns in a way that is forwards-compatible with a generic string pattern matching API:
- Methods that are using the primary name for their operation are marked as `#[stable]`, as they can be upgraded to a full `Pattern` API later without existing code breaking. Example: `contains(&str)`
- Methods that are using a more specific name in order to not clash with the primary one are marked as `#[unstable]`, as they will likely be removed once their functionality is merged into the primary one. Example: `contains_char<C: CharEq>(C)`
- The method docs got changed to consistently refer to the pattern types as a pattern.
- Methods whose names do not match in the context of the more generic API got renamed. Example: `trim_chars -> trim_matches` 

Additionally, all methods returning iterators got changed to return unique new types with changed names in accordance with the new naming guidelines.

See also https://github.com/rust-lang/rfcs/pull/528

Due to some deprecations and type changes, this is a 

[breaking-change]
This commit is contained in:
bors 2014-12-29 18:02:30 +00:00
commit 19f73b4ef6
5 changed files with 274 additions and 172 deletions

View File

@ -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)
}
/// Returns a string with trailing `chars_to_trim` removed.
/// 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 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)
#[stable]
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)
#[stable]
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)
}

View File

@ -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> {}

View File

@ -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| {

View File

@ -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> =

View File

@ -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())
}
}