std: Tweak some unstable features of `str`

This commit clarifies some of the unstable features in the `str` module by
moving them out of the blanket `core` and `collections` features.

The following methods were moved to the `str_char` feature which generally
encompasses decoding specific characters from a `str` and dealing with the
result. It is unclear if any of these methods need to be stabilized for 1.0 and
the most conservative route for now is to continue providing them but to leave
them as unstable under a more specific name.

* `is_char_boundary`
* `char_at`
* `char_range_at`
* `char_at_reverse`
* `char_range_at_reverse`
* `slice_shift_char`

The following methods were moved into the generic `unicode` feature as they are
specifically enabled by the `unicode` crate itself.

* `nfd_chars`
* `nfkd_chars`
* `nfc_chars`
* `graphemes`
* `grapheme_indices`
* `width`
This commit is contained in:
Alex Crichton 2015-03-10 16:29:02 -07:00
parent c64d671671
commit aa88da6317
16 changed files with 156 additions and 92 deletions

View File

@ -1052,22 +1052,22 @@ fn scan_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
if *idx >= haystack.len() {
return false;
}
let range = haystack.char_range_at(*idx);
if range.ch != needle {
let ch = haystack.char_at(*idx);
if ch != needle {
return false;
}
*idx = range.next;
*idx += ch.len_utf8();
return true;
}
fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
let mut i = *idx;
while i < haystack.len() {
let range = haystack.char_range_at(i);
if range.ch < '0' || '9' < range.ch {
let ch = haystack.char_at(i);
if ch < '0' || '9' < ch {
break;
}
i = range.next;
i += ch.len_utf8();
}
if i == *idx {
return false;
@ -1083,9 +1083,9 @@ fn scan_string(haystack: &str, needle: &str, idx: &mut uint) -> bool {
if haystack_i >= haystack.len() {
return false;
}
let range = haystack.char_range_at(haystack_i);
haystack_i = range.next;
if !scan_char(needle, range.ch, &mut needle_i) {
let ch = haystack.char_at(haystack_i);
haystack_i += ch.len_utf8();
if !scan_char(needle, ch, &mut needle_i) {
return false;
}
}

View File

@ -35,6 +35,7 @@
#![feature(unique)]
#![feature(unsafe_no_drop_flag)]
#![feature(step_by)]
#![feature(str_char)]
#![cfg_attr(test, feature(rand, rustc_private, test))]
#![cfg_attr(test, allow(deprecated))] // rand

View File

@ -175,7 +175,9 @@ enum DecompositionType {
///
/// For use with the `std::iter` module.
#[derive(Clone)]
#[unstable(feature = "collections")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
pub struct Decompositions<'a> {
kind: DecompositionType,
iter: Chars<'a>,
@ -266,7 +268,9 @@ enum RecompositionState {
///
/// For use with the `std::iter` module.
#[derive(Clone)]
#[unstable(feature = "collections")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
pub struct Recompositions<'a> {
iter: Decompositions<'a>,
state: RecompositionState,
@ -472,8 +476,9 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// Returns an iterator over the string in Unicode Normalization Form D
/// (canonical decomposition).
#[inline]
#[unstable(feature = "collections",
reason = "this functionality may be moved to libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
fn nfd_chars(&self) -> Decompositions {
Decompositions {
iter: self[..].chars(),
@ -486,8 +491,9 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// Returns an iterator over the string in Unicode Normalization Form KD
/// (compatibility decomposition).
#[inline]
#[unstable(feature = "collections",
reason = "this functionality may be moved to libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
fn nfkd_chars(&self) -> Decompositions {
Decompositions {
iter: self[..].chars(),
@ -500,8 +506,9 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// An Iterator over the string in Unicode Normalization Form C
/// (canonical decomposition followed by canonical composition).
#[inline]
#[unstable(feature = "collections",
reason = "this functionality may be moved to libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
fn nfc_chars(&self) -> Recompositions {
Recompositions {
iter: self.nfd_chars(),
@ -515,8 +522,9 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// An Iterator over the string in Unicode Normalization Form KC
/// (compatibility decomposition followed by canonical composition).
#[inline]
#[unstable(feature = "collections",
reason = "this functionality may be moved to libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
fn nfkc_chars(&self) -> Recompositions {
Recompositions {
iter: self.nfkd_chars(),
@ -1023,8 +1031,11 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// // third byte of `老`
/// assert!(!s.is_char_boundary(8));
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "it is unclear whether this method pulls its weight \
with the existence of the char_indices iterator or \
this method may want to be replaced with checked \
slicing")]
fn is_char_boundary(&self, index: usize) -> bool {
core_str::StrExt::is_char_boundary(&self[..], index)
}
@ -1069,8 +1080,10 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// 14: a
/// 15: m
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "often replaced by char_indices, this method may \
be removed in favor of just char_at() or eventually \
removed altogether")]
fn char_range_at(&self, start: usize) -> CharRange {
core_str::StrExt::char_range_at(&self[..], start)
}
@ -1117,8 +1130,10 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// 6: 华
/// 3: 中
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "often replaced by char_indices, this method may \
be removed in favor of just char_at() or eventually \
removed altogether")]
fn char_range_at_reverse(&self, start: usize) -> CharRange {
core_str::StrExt::char_range_at_reverse(&self[..], start)
}
@ -1137,8 +1152,12 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// assert_eq!(s.char_at(1), 'b');
/// assert_eq!(s.char_at(2), 'π');
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "frequently replaced by the chars() iterator, this \
method may be removed or possibly renamed in the \
future; it is normally replaced by chars/char_indices \
iterators or by getting the first char from a \
subslice")]
fn char_at(&self, i: usize) -> char {
core_str::StrExt::char_at(&self[..], i)
}
@ -1157,8 +1176,10 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// assert_eq!(s.char_at_reverse(1), 'a');
/// assert_eq!(s.char_at_reverse(2), 'b');
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "see char_at for more details, but reverse semantics \
are also somewhat unclear, especially with which \
cases generate panics")]
fn char_at_reverse(&self, i: usize) -> char {
core_str::StrExt::char_at_reverse(&self[..], i)
}
@ -1297,8 +1318,10 @@ pub trait StrExt: Index<RangeFull, Output = str> {
/// assert_eq!(c, 'ö');
/// assert_eq!(s2, "we 老虎 Léopard");
/// ```
#[unstable(feature = "collections",
reason = "awaiting conventions about shifting and slices")]
#[unstable(feature = "str_char",
reason = "awaiting conventions about shifting and slices and \
may not be warranted with the existence of the chars \
and/or char_indices iterators")]
fn slice_shift_char(&self) -> Option<(char, &str)> {
core_str::StrExt::slice_shift_char(&self[..])
}
@ -1421,8 +1444,9 @@ pub trait StrExt: Index<RangeFull, Output = str> {
///
/// assert_eq!(gr2.as_slice(), b);
/// ```
#[unstable(feature = "collections",
reason = "this functionality may only be provided by libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
fn graphemes(&self, is_extended: bool) -> Graphemes {
UnicodeStr::graphemes(&self[..], is_extended)
}
@ -1438,8 +1462,9 @@ pub trait StrExt: Index<RangeFull, Output = str> {
///
/// assert_eq!(gr_inds.as_slice(), b);
/// ```
#[unstable(feature = "collections",
reason = "this functionality may only be provided by libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
fn grapheme_indices(&self, is_extended: bool) -> GraphemeIndices {
UnicodeStr::grapheme_indices(&self[..], is_extended)
}
@ -1467,13 +1492,15 @@ pub trait StrExt: Index<RangeFull, Output = str> {
///
/// Control characters have zero width.
///
/// `is_cjk` determines behavior for characters in the Ambiguous category: if `is_cjk` is
/// `true`, these are 2 columns wide; otherwise, they are 1. In CJK locales, `is_cjk` should be
/// `true`, else it should be `false`.
/// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) recommends that these
/// characters be treated as 1 column (i.e., `is_cjk = false`) if the locale is unknown.
#[unstable(feature = "collections",
reason = "this functionality may only be provided by libunicode")]
/// `is_cjk` determines behavior for characters in the Ambiguous category:
/// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
/// In CJK locales, `is_cjk` should be `true`, else it should be `false`.
/// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
/// recommends that these characters be treated as 1 column (i.e., `is_cjk =
/// false`) if the locale is unknown.
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
fn width(&self, is_cjk: bool) -> usize {
UnicodeStr::width(&self[..], is_cjk)
}
@ -1615,8 +1642,9 @@ impl str {
/// Returns an iterator over the string in Unicode Normalization Form D
/// (canonical decomposition).
#[inline]
#[unstable(feature = "collections",
reason = "this functionality may be moved to libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
pub fn nfd_chars(&self) -> Decompositions {
Decompositions {
iter: self[..].chars(),
@ -1629,8 +1657,9 @@ impl str {
/// Returns an iterator over the string in Unicode Normalization Form KD
/// (compatibility decomposition).
#[inline]
#[unstable(feature = "collections",
reason = "this functionality may be moved to libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
pub fn nfkd_chars(&self) -> Decompositions {
Decompositions {
iter: self[..].chars(),
@ -1643,8 +1672,9 @@ impl str {
/// An Iterator over the string in Unicode Normalization Form C
/// (canonical decomposition followed by canonical composition).
#[inline]
#[unstable(feature = "collections",
reason = "this functionality may be moved to libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
pub fn nfc_chars(&self) -> Recompositions {
Recompositions {
iter: self.nfd_chars(),
@ -1658,8 +1688,9 @@ impl str {
/// An Iterator over the string in Unicode Normalization Form KC
/// (compatibility decomposition followed by canonical composition).
#[inline]
#[unstable(feature = "collections",
reason = "this functionality may be moved to libunicode")]
#[unstable(feature = "unicode",
reason = "this functionality may be replaced with a more generic \
unicode crate on crates.io")]
pub fn nfkc_chars(&self) -> Recompositions {
Recompositions {
iter: self.nfkd_chars(),
@ -2172,8 +2203,11 @@ impl str {
/// // third byte of `老`
/// assert!(!s.is_char_boundary(8));
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "it is unclear whether this method pulls its weight \
with the existence of the char_indices iterator or \
this method may want to be replaced with checked \
slicing")]
pub fn is_char_boundary(&self, index: usize) -> bool {
core_str::StrExt::is_char_boundary(&self[..], index)
}
@ -2218,8 +2252,10 @@ impl str {
/// 14: a
/// 15: m
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "often replaced by char_indices, this method may \
be removed in favor of just char_at() or eventually \
removed altogether")]
pub fn char_range_at(&self, start: usize) -> CharRange {
core_str::StrExt::char_range_at(&self[..], start)
}
@ -2266,8 +2302,10 @@ impl str {
/// 6: 华
/// 3: 中
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "often replaced by char_indices, this method may \
be removed in favor of just char_at_reverse() or \
eventually removed altogether")]
pub fn char_range_at_reverse(&self, start: usize) -> CharRange {
core_str::StrExt::char_range_at_reverse(&self[..], start)
}
@ -2286,8 +2324,12 @@ impl str {
/// assert_eq!(s.char_at(1), 'b');
/// assert_eq!(s.char_at(2), 'π');
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "frequently replaced by the chars() iterator, this \
method may be removed or possibly renamed in the \
future; it is normally replaced by chars/char_indices \
iterators or by getting the first char from a \
subslice")]
pub fn char_at(&self, i: usize) -> char {
core_str::StrExt::char_at(&self[..], i)
}
@ -2306,8 +2348,10 @@ impl str {
/// assert_eq!(s.char_at_reverse(1), 'a');
/// assert_eq!(s.char_at_reverse(2), 'b');
/// ```
#[unstable(feature = "collections",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "see char_at for more details, but reverse semantics \
are also somewhat unclear, especially with which \
cases generate panics")]
pub fn char_at_reverse(&self, i: usize) -> char {
core_str::StrExt::char_at_reverse(&self[..], i)
}
@ -2446,8 +2490,10 @@ impl str {
/// assert_eq!(c, 'ö');
/// assert_eq!(s2, "we 老虎 Léopard");
/// ```
#[unstable(feature = "collections",
reason = "awaiting conventions about shifting and slices")]
#[unstable(feature = "str_char",
reason = "awaiting conventions about shifting and slices and \
may not be warranted with the existence of the chars \
and/or char_indices iterators")]
pub fn slice_shift_char(&self) -> Option<(char, &str)> {
core_str::StrExt::slice_shift_char(&self[..])
}
@ -2570,7 +2616,7 @@ impl str {
///
/// assert_eq!(gr2.as_slice(), b);
/// ```
#[unstable(feature = "collections",
#[unstable(feature = "unicode",
reason = "this functionality may only be provided by libunicode")]
pub fn graphemes(&self, is_extended: bool) -> Graphemes {
UnicodeStr::graphemes(&self[..], is_extended)
@ -2587,7 +2633,7 @@ impl str {
///
/// assert_eq!(gr_inds.as_slice(), b);
/// ```
#[unstable(feature = "collections",
#[unstable(feature = "unicode",
reason = "this functionality may only be provided by libunicode")]
pub fn grapheme_indices(&self, is_extended: bool) -> GraphemeIndices {
UnicodeStr::grapheme_indices(&self[..], is_extended)
@ -2621,7 +2667,7 @@ impl str {
/// `true`, else it should be `false`.
/// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) recommends that these
/// characters be treated as 1 column (i.e., `is_cjk = false`) if the locale is unknown.
#[unstable(feature = "collections",
#[unstable(feature = "unicode",
reason = "this functionality may only be provided by libunicode")]
pub fn width(&self, is_cjk: bool) -> usize {
UnicodeStr::width(&self[..], is_cjk)

View File

@ -29,7 +29,7 @@ use unicode::str as unicode_str;
use unicode::str::Utf16Item;
use borrow::{Cow, IntoCow};
use str::{self, CharRange, FromStr, Utf8Error};
use str::{self, FromStr, Utf8Error};
use vec::{DerefVec, Vec, as_vec};
/// A growable string stored as a UTF-8 encoded buffer.
@ -561,9 +561,9 @@ impl String {
return None
}
let CharRange {ch, next} = self.char_range_at_reverse(len);
let ch = self.char_at_reverse(len);
unsafe {
self.vec.set_len(next);
self.vec.set_len(len - ch.len_utf8());
}
Some(ch)
}
@ -595,7 +595,8 @@ impl String {
let len = self.len();
assert!(idx <= len);
let CharRange { ch, next } = self.char_range_at(idx);
let ch = self.char_at(idx);
let next = idx + ch.len_utf8();
unsafe {
ptr::copy(self.vec.as_mut_ptr().offset(idx as isize),
self.vec.as_ptr().offset(next as isize),

View File

@ -18,6 +18,7 @@
use self::OldSearcher::{TwoWay, TwoWayLong};
use char::CharExt;
use clone::Clone;
use cmp::{self, Eq};
use default::Default;
@ -1112,8 +1113,10 @@ static UTF8_CHAR_WIDTH: [u8; 256] = [
/// the next `char` in a string. This can be used as a data structure
/// for iterating over the UTF-8 bytes of a string.
#[derive(Copy)]
#[unstable(feature = "core",
reason = "naming is uncertain with container conventions")]
#[unstable(feature = "str_char",
reason = "existence of this struct is uncertain as it is frequently \
able to be replaced with char.len_utf8() and/or \
char/char_indices iterators")]
pub struct CharRange {
/// Current `char`
pub ch: char,
@ -1646,8 +1649,8 @@ impl StrExt for str {
if self.is_empty() {
None
} else {
let CharRange {ch, next} = self.char_range_at(0);
let next_s = unsafe { self.slice_unchecked(next, self.len()) };
let ch = self.char_at(0);
let next_s = unsafe { self.slice_unchecked(ch.len_utf8(), self.len()) };
Some((ch, next_s))
}
}

View File

@ -92,11 +92,10 @@
html_playground_url = "http://play.rust-lang.org/")]
#![deny(missing_docs)]
#![feature(collections)]
#![feature(int_uint)]
#![feature(staged_api)]
#![feature(core)]
#![feature(str_words)]
#![feature(str_char)]
#![cfg_attr(test, feature(rustc_private))]
#[cfg(test)] #[macro_use] extern crate log;
@ -620,8 +619,8 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result {
let mut j = 1;
names = Vec::new();
while j < curlen {
let range = cur.char_range_at(j);
let opt = Short(range.ch);
let ch = cur.char_at(j);
let opt = Short(ch);
/* In a series of potential options (eg. -aheJ), if we
see one which takes an argument, we assume all
@ -642,12 +641,13 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result {
No => false
};
if arg_follows && range.next < curlen {
i_arg = Some((&cur[range.next..curlen]).to_string());
let next = j + ch.len_utf8();
if arg_follows && next < curlen {
i_arg = Some((&cur[next..curlen]).to_string());
break;
}
j = range.next;
j = next;
}
}
let mut name_pos = 0;

View File

@ -42,6 +42,7 @@
#![feature(io)]
#![feature(path_ext)]
#![feature(str_words)]
#![feature(str_char)]
#![cfg_attr(test, feature(test))]
extern crate arena;

View File

@ -38,6 +38,7 @@
#![feature(exit_status)]
#![feature(io)]
#![feature(set_stdio)]
#![feature(unicode)]
extern crate arena;
extern crate flate;

View File

@ -41,6 +41,7 @@
#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(std_misc)]
#![feature(str_char)]
#![cfg_attr(test, feature(test))]
extern crate syntax;

View File

@ -37,6 +37,7 @@ Core encoding and decoding interfaces.
#![feature(staged_api)]
#![feature(std_misc)]
#![feature(unicode)]
#![feature(str_char)]
#![cfg_attr(test, feature(test))]
// test harness access

View File

@ -127,6 +127,7 @@
#![feature(int_uint)]
#![feature(unique)]
#![feature(allow_internal_unstable)]
#![feature(str_char)]
#![cfg_attr(test, feature(test, rustc_private))]
// Don't link to std. We are std.

View File

@ -38,6 +38,7 @@
#![feature(std_misc)]
#![feature(unicode)]
#![feature(path_ext)]
#![feature(str_char)]
extern crate arena;
extern crate fmt_macros;

View File

@ -20,7 +20,6 @@ use parse::lexer;
use print::pprust;
use std::io::Read;
use std::str;
use std::usize;
#[derive(Clone, Copy, PartialEq)]
@ -210,11 +209,11 @@ fn all_whitespace(s: &str, col: CharPos) -> Option<usize> {
let mut col = col.to_usize();
let mut cursor: usize = 0;
while col > 0 && cursor < len {
let r: str::CharRange = s.char_range_at(cursor);
if !r.ch.is_whitespace() {
let ch = s.char_at(cursor);
if !ch.is_whitespace() {
return None;
}
cursor = r.next;
cursor += ch.len_utf8();
col -= 1;
}
return Some(cursor);

View File

@ -22,7 +22,6 @@ use std::fmt;
use std::mem::replace;
use std::num;
use std::rc::Rc;
use std::str;
pub use ext::tt::transcribe::{TtReader, new_tt_reader, new_tt_reader_with_doc_flag};
@ -291,7 +290,8 @@ impl<'a> StringReader<'a> {
s: &'b str, errmsg: &'b str) -> Cow<'b, str> {
let mut i = 0;
while i < s.len() {
let str::CharRange { ch, next } = s.char_range_at(i);
let ch = s.char_at(i);
let next = i + ch.len_utf8();
if ch == '\r' {
if next < s.len() && s.char_at(next) == '\n' {
return translate_crlf_(self, start, s, errmsg, i).into_cow();
@ -309,7 +309,8 @@ impl<'a> StringReader<'a> {
let mut buf = String::with_capacity(s.len());
let mut j = 0;
while i < s.len() {
let str::CharRange { ch, next } = s.char_range_at(i);
let ch = s.char_at(i);
let next = i + ch.len_utf8();
if ch == '\r' {
if j < i { buf.push_str(&s[j..i]); }
j = next;
@ -335,10 +336,11 @@ impl<'a> StringReader<'a> {
if current_byte_offset < self.source_text.len() {
assert!(self.curr.is_some());
let last_char = self.curr.unwrap();
let next = self.source_text.char_range_at(current_byte_offset);
let byte_offset_diff = next.next - current_byte_offset;
let ch = self.source_text.char_at(current_byte_offset);
let next = current_byte_offset + ch.len_utf8();
let byte_offset_diff = next - current_byte_offset;
self.pos = self.pos + Pos::from_usize(byte_offset_diff);
self.curr = Some(next.ch);
self.curr = Some(ch);
self.col = self.col + CharPos(1);
if last_char == '\n' {
self.filemap.next_line(self.last_pos);
@ -370,7 +372,7 @@ impl<'a> StringReader<'a> {
let offset = self.byte_offset(self.pos).to_usize();
let s = &self.source_text[..];
if offset >= s.len() { return None }
let str::CharRange { next, .. } = s.char_range_at(offset);
let next = offset + s.char_at(offset).len_utf8();
if next < s.len() {
Some(s.char_at(next))
} else {

View File

@ -60,6 +60,7 @@
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(std_misc)]
#![feature(str_char)]
#![feature(path_ext)]
#![cfg_attr(windows, feature(libc))]

View File

@ -244,7 +244,7 @@ impl<'a> Iterator for Graphemes<'a> {
}
self.cat = if take_curr {
idx = self.string.char_range_at(idx).next;
idx = idx + len_utf8(self.string.char_at(idx));
None
} else {
Some(cat)
@ -256,6 +256,11 @@ impl<'a> Iterator for Graphemes<'a> {
}
}
#[cfg(stage0)]
fn len_utf8(c: char) -> usize { UCharExt::len_utf8(c) }
#[cfg(not(stage0))]
fn len_utf8(c: char) -> usize { c.len_utf8() }
impl<'a> DoubleEndedIterator for Graphemes<'a> {
#[inline]
fn next_back(&mut self) -> Option<&'a str> {