diff options
| author | QuietMisdreavus <grey@quietmisdreavus.net> | 2017-04-09 10:38:38 -0500 |
|---|---|---|
| committer | QuietMisdreavus <grey@quietmisdreavus.net> | 2017-04-09 10:38:38 -0500 |
| commit | 8dd4c44ef6c851afcc9651c9b32df005e35d0d1d (patch) | |
| tree | 5dc8ec96361b673f8d4162821a97f8f021d83436 /src/libcore/str | |
| parent | bfd01b7f40ae2cbfe9acbc1d10e79ffe16870df8 (diff) | |
| parent | 2c48ae6f7ffae392d85c86240c67f49df01f44fd (diff) | |
merge with master to pick up pulldown switch
Diffstat (limited to 'src/libcore/str')
| -rw-r--r-- | src/libcore/str/mod.rs | 517 |
1 files changed, 433 insertions, 84 deletions
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 2919adc1cbc..352cc926994 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -18,22 +18,56 @@ use self::pattern::Pattern; use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char; +use convert::TryFrom; use fmt; use iter::{Map, Cloned, FusedIterator}; use mem; -use slice; +use slice::{self, SliceIndex}; pub mod pattern; /// A trait to abstract the idea of creating a new instance of a type from a /// string. /// -/// `FromStr`'s [`from_str()`] method is often used implicitly, through -/// [`str`]'s [`parse()`] method. See [`parse()`]'s documentation for examples. +/// `FromStr`'s [`from_str`] method is often used implicitly, through +/// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples. /// -/// [`from_str()`]: #tymethod.from_str +/// [`from_str`]: #tymethod.from_str /// [`str`]: ../../std/primitive.str.html -/// [`parse()`]: ../../std/primitive.str.html#method.parse +/// [`parse`]: ../../std/primitive.str.html#method.parse +/// +/// # Examples +/// +/// Basic implementation of `FromStr` on an example `Point` type: +/// +/// ``` +/// use std::str::FromStr; +/// use std::num::ParseIntError; +/// +/// #[derive(Debug, PartialEq)] +/// struct Point { +/// x: i32, +/// y: i32 +/// } +/// +/// impl FromStr for Point { +/// type Err = ParseIntError; +/// +/// fn from_str(s: &str) -> Result<Self, Self::Err> { +/// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) +/// .split(",") +/// .collect(); +/// +/// let x_fromstr = coords[0].parse::<i32>()?; +/// let y_fromstr = coords[1].parse::<i32>()?; +/// +/// Ok(Point { x: x_fromstr, y: y_fromstr }) +/// } +/// } +/// +/// let p = Point::from_str("(1,2)"); +/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait FromStr: Sized { /// The associated error which can be returned from parsing. @@ -100,7 +134,9 @@ impl FromStr for bool { } } -/// An error returned when parsing a `bool` from a string fails. +/// An error returned when parsing a `bool` using [`from_str`] fails +/// +/// [`from_str`]: ../../std/primitive.bool.html#method.from_str #[derive(Debug, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct ParseBoolError { _priv: () } @@ -116,11 +152,16 @@ impl fmt::Display for ParseBoolError { Section: Creating a string */ -/// Errors which can occur when attempting to interpret a sequence of `u8` +/// Errors which can occur when attempting to interpret a sequence of [`u8`] /// as a string. /// -/// As such, the `from_utf8` family of functions and methods for both `String`s -/// and `&str`s make use of this error, for example. +/// [`u8`]: ../../std/primitive.u8.html +/// +/// As such, the `from_utf8` family of functions and methods for both [`String`]s +/// and [`&str`]s make use of this error, for example. +/// +/// [`String`]: ../../std/string/struct.String.html#method.from_utf8 +/// [`&str`]: ../../std/str/fn.from_utf8.html #[derive(Copy, Eq, PartialEq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { @@ -174,27 +215,34 @@ impl Utf8Error { /// Converts a slice of bytes to a string slice. /// -/// A string slice (`&str`) is made of bytes (`u8`), and a byte slice (`&[u8]`) -/// is made of bytes, so this function converts between the two. Not all byte -/// slices are valid string slices, however: `&str` requires that it is valid -/// UTF-8. `from_utf8()` checks to ensure that the bytes are valid UTF-8, and -/// then does the conversion. +/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice +/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between +/// the two. Not all byte slices are valid string slices, however: [`&str`] requires +/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid +/// UTF-8, and then does the conversion. +/// +/// [`&str`]: ../../std/primitive.str.html +/// [`u8`]: ../../std/primitive.u8.html +/// [byteslice]: ../../std/primitive.slice.html /// /// If you are sure that the byte slice is valid UTF-8, and you don't want to /// incur the overhead of the validity check, there is an unsafe version of -/// this function, [`from_utf8_unchecked()`][fromutf8u], which has the same +/// this function, [`from_utf8_unchecked`][fromutf8u], which has the same /// behavior but skips the check. /// /// [fromutf8u]: fn.from_utf8_unchecked.html /// /// If you need a `String` instead of a `&str`, consider -/// [`String::from_utf8()`][string]. +/// [`String::from_utf8`][string]. /// /// [string]: ../../std/string/struct.String.html#method.from_utf8 /// -/// Because you can stack-allocate a `[u8; N]`, and you can take a `&[u8]` of -/// it, this function is one way to have a stack-allocated string. There is -/// an example of this in the examples section below. +/// Because you can stack-allocate a `[u8; N]`, and you can take a +/// [`&[u8]`][byteslice] of it, this function is one way to have a +/// stack-allocated string. There is an example of this in the +/// examples section below. +/// +/// [byteslice]: ../../std/primitive.slice.html /// /// # Errors /// @@ -283,7 +331,7 @@ unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8. /// -/// See the safe version, [`from_utf8()`][fromutf8], for more information. +/// See the safe version, [`from_utf8`][fromutf8], for more information. /// /// [fromutf8]: fn.from_utf8.html /// @@ -291,7 +339,9 @@ unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { /// /// This function is unsafe because it does not check that the bytes passed to /// it are valid UTF-8. If this constraint is violated, undefined behavior -/// results, as the rest of Rust assumes that `&str`s are valid UTF-8. +/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8. +/// +/// [`&str`]: ../../std/primitive.str.html /// /// # Examples /// @@ -331,24 +381,28 @@ impl fmt::Display for Utf8Error { Section: Iterators */ -/// Iterator for the char (representing *Unicode Scalar Values*) of a string +/// An iterator over the [`char`]s of a string slice. +/// +/// [`char`]: ../../std/primitive.char.html /// -/// Created with the method [`chars()`]. +/// This struct is created by the [`chars`] method on [`str`]. +/// See its documentation for more. /// -/// [`chars()`]: ../../std/primitive.str.html#method.chars +/// [`chars`]: ../../std/primitive.str.html#method.chars +/// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Chars<'a> { iter: slice::Iter<'a, u8> } -/// Return the initial codepoint accumulator for the first byte. +/// Returns the initial codepoint accumulator for the first byte. /// The first byte is special, only want bottom 5 bits for width 2, 4 bits /// for width 3, and 3 bits for width 4. #[inline] fn utf8_first_byte(byte: u8, width: u32) -> u32 { (byte & (0x7F >> width)) as u32 } -/// Return the value of `ch` updated with continuation byte `byte`. +/// Returns the value of `ch` updated with continuation byte `byte`. #[inline] fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { (ch << 6) | (byte & CONT_MASK) as u32 } @@ -515,7 +569,15 @@ impl<'a> Chars<'a> { } } -/// Iterator for a string's characters and their byte offsets. +/// An iterator over the [`char`]s of a string slice, and their positions. +/// +/// [`char`]: ../../std/primitive.char.html +/// +/// This struct is created by the [`char_indices`] method on [`str`]. +/// See its documentation for more. +/// +/// [`char_indices`]: ../../std/primitive.str.html#method.char_indices +/// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CharIndices<'a> { @@ -587,12 +649,13 @@ impl<'a> CharIndices<'a> { } } -/// External iterator for a string's bytes. -/// Use with the `std::iter` module. +/// An iterator over the bytes of a string slice. /// -/// Created with the method [`bytes()`]. +/// This struct is created by the [`bytes`] method on [`str`]. +/// See its documentation for more. /// -/// [`bytes()`]: ../../std/primitive.str.html#method.bytes +/// [`bytes`]: ../../std/primitive.str.html#method.bytes +/// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Bytes<'a>(Cloned<slice::Iter<'a, u8>>); @@ -925,14 +988,14 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method [`split()`]. + /// Created with the method [`split`]. /// - /// [`split()`]: ../../std/primitive.str.html#method.split + /// [`split`]: ../../std/primitive.str.html#method.split struct Split; reverse: - /// Created with the method [`rsplit()`]. + /// Created with the method [`rsplit`]. /// - /// [`rsplit()`]: ../../std/primitive.str.html#method.rsplit + /// [`rsplit`]: ../../std/primitive.str.html#method.rsplit struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -943,14 +1006,14 @@ generate_pattern_iterators! { generate_pattern_iterators! { forward: - /// Created with the method [`split_terminator()`]. + /// Created with the method [`split_terminator`]. /// - /// [`split_terminator()`]: ../../std/primitive.str.html#method.split_terminator + /// [`split_terminator`]: ../../std/primitive.str.html#method.split_terminator struct SplitTerminator; reverse: - /// Created with the method [`rsplit_terminator()`]. + /// Created with the method [`rsplit_terminator`]. /// - /// [`rsplit_terminator()`]: ../../std/primitive.str.html#method.rsplit_terminator + /// [`rsplit_terminator`]: ../../std/primitive.str.html#method.rsplit_terminator struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -1003,14 +1066,14 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method [`splitn()`]. + /// Created with the method [`splitn`]. /// - /// [`splitn()`]: ../../std/primitive.str.html#method.splitn + /// [`splitn`]: ../../std/primitive.str.html#method.splitn struct SplitN; reverse: - /// Created with the method [`rsplitn()`]. + /// Created with the method [`rsplitn`]. /// - /// [`rsplitn()`]: ../../std/primitive.str.html#method.rsplitn + /// [`rsplitn`]: ../../std/primitive.str.html#method.rsplitn struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -1054,14 +1117,14 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method [`match_indices()`]. + /// Created with the method [`match_indices`]. /// - /// [`match_indices()`]: ../../std/primitive.str.html#method.match_indices + /// [`match_indices`]: ../../std/primitive.str.html#method.match_indices struct MatchIndices; reverse: - /// Created with the method [`rmatch_indices()`]. + /// Created with the method [`rmatch_indices`]. /// - /// [`rmatch_indices()`]: ../../std/primitive.str.html#method.rmatch_indices + /// [`rmatch_indices`]: ../../std/primitive.str.html#method.rmatch_indices struct RMatchIndices; stability: #[stable(feature = "str_match_indices", since = "1.5.0")] @@ -1107,14 +1170,14 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method [`matches()`]. + /// Created with the method [`matches`]. /// - /// [`matches()`]: ../../std/primitive.str.html#method.matches + /// [`matches`]: ../../std/primitive.str.html#method.matches struct Matches; reverse: - /// Created with the method [`rmatches()`]. + /// Created with the method [`rmatches`]. /// - /// [`rmatches()`]: ../../std/primitive.str.html#method.rmatches + /// [`rmatches`]: ../../std/primitive.str.html#method.rmatches struct RMatches; stability: #[stable(feature = "str_matches", since = "1.2.0")] @@ -1123,9 +1186,13 @@ generate_pattern_iterators! { delegate double ended; } -/// Created with the method [`lines()`]. +/// An iterator over the lines of a string, as string slices. +/// +/// This struct is created with the [`lines`] method on [`str`]. +/// See its documentation for more. /// -/// [`lines()`]: ../../std/primitive.str.html#method.lines +/// [`lines`]: ../../std/primitive.str.html#method.lines +/// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Lines<'a>(Map<SplitTerminator<'a, char>, LinesAnyMap>); @@ -1156,9 +1223,9 @@ impl<'a> DoubleEndedIterator for Lines<'a> { #[unstable(feature = "fused", issue = "35602")] impl<'a> FusedIterator for Lines<'a> {} -/// Created with the method [`lines_any()`]. +/// Created with the method [`lines_any`]. /// -/// [`lines_any()`]: ../../std/primitive.str.html#method.lines_any +/// [`lines_any`]: ../../std/primitive.str.html#method.lines_any #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")] #[derive(Clone, Debug)] @@ -1243,13 +1310,13 @@ Section: UTF-8 validation // use truncation to fit u64 into usize const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; -/// Return `true` if any byte in the word `x` is nonascii (>= 128). +/// Returns `true` if any byte in the word `x` is nonascii (>= 128). #[inline] fn contains_nonascii(x: usize) -> bool { (x & NONASCII_MASK) != 0 } -/// Walk through `iter` checking that it's a valid UTF-8 sequence, +/// Walks through `iter` checking that it's a valid UTF-8 sequence, /// returning `true` in that case, or, if it is invalid, `false` with /// `iter` reset such that it is pointing at the first byte in the /// invalid sequence. @@ -1388,16 +1455,16 @@ static UTF8_CHAR_WIDTH: [u8; 256] = [ 4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF ]; -/// Given a first byte, determine how many bytes are in this UTF-8 character +/// Given a first byte, determines how many bytes are in this UTF-8 character. #[unstable(feature = "str_internals", issue = "0")] #[inline] pub fn utf8_char_width(b: u8) -> usize { return UTF8_CHAR_WIDTH[b as usize] as usize; } -/// Mask of the value bits of a continuation byte +/// Mask of the value bits of a continuation byte. const CONT_MASK: u8 = 0b0011_1111; -/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte +/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte. const TAG_CONT_U8: u8 = 0b1000_0000; /* @@ -1407,6 +1474,8 @@ Section: Trait implementations mod traits { use cmp::Ordering; use ops; + use mem; + use slice::{self, SliceIndex}; use str::eq_slice; /// Implements ordering of strings. @@ -1489,14 +1558,7 @@ mod traits { type Output = str; #[inline] fn index(&self, index: ops::Range<usize>) -> &str { - // is_char_boundary checks that the index is in [0, .len()] - if index.start <= index.end && - self.is_char_boundary(index.start) && - self.is_char_boundary(index.end) { - unsafe { self.slice_unchecked(index.start, index.end) } - } else { - super::slice_error_fail(self, index.start, index.end) - } + index.index(self) } } @@ -1518,14 +1580,7 @@ mod traits { impl ops::IndexMut<ops::Range<usize>> for str { #[inline] fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str { - // is_char_boundary checks that the index is in [0, .len()] - if index.start <= index.end && - self.is_char_boundary(index.start) && - self.is_char_boundary(index.end) { - unsafe { self.slice_mut_unchecked(index.start, index.end) } - } else { - super::slice_error_fail(self, index.start, index.end) - } + index.index_mut(self) } } @@ -1693,8 +1748,276 @@ mod traits { self.index_mut(0...index.end) } } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex<str> for ops::RangeFull { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + Some(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + Some(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } + } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex<str> for ops::Range<usize> { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = self.end - self.start; + super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = self.end - self.start; + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, self.end); + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + // is_char_boundary checks that the index is in [0, .len()] + // canot reuse `get` as above, because of NLL trouble + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, self.end) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex<str> for ops::RangeTo<usize> { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr(); + super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr(); + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end; + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex<str> for ops::RangeFrom<usize> { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.start) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.start) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = slice.len() - self.start; + super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = slice.len() - self.start; + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, slice.len()); + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.start) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, slice.len()) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex<str> for ops::RangeInclusive<usize> { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_mut(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_unchecked(slice) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_unchecked_mut(slice) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.index_mut(slice) + } + } + + + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex<str> for ops::RangeToInclusive<usize> { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end + 1) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end + 1) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr(); + super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end + 1)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr(); + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end + 1; + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end + 1) + } + } + } + } + /// Methods for string slices #[allow(missing_docs)] #[doc(hidden)] @@ -1744,6 +2067,14 @@ pub trait StrExt { #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")] #[allow(deprecated)] fn lines_any(&self) -> LinesAny; + #[unstable(feature = "str_checked_slicing", issue = "39932")] + fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "39932")] + fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "39932")] + unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output; + #[unstable(feature = "str_checked_slicing", issue = "39932")] + unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output; #[stable(feature = "core", since = "1.6.0")] unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str; #[stable(feature = "core", since = "1.6.0")] @@ -1782,7 +2113,7 @@ pub trait StrExt { #[stable(feature = "core", since = "1.6.0")] fn is_empty(&self) -> bool; #[stable(feature = "core", since = "1.6.0")] - fn parse<T: FromStr>(&self) -> Result<T, T::Err>; + fn parse<'a, T: TryFrom<&'a str>>(&'a self) -> Result<T, T::Error>; } // truncate `&str` to length at most equal to `max` @@ -1934,17 +2265,33 @@ impl StrExt for str { } #[inline] + fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> { + i.get(self) + } + + #[inline] + fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> { + i.get_mut(self) + } + + #[inline] + unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output { + i.get_unchecked(self) + } + + #[inline] + unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output { + i.get_unchecked_mut(self) + } + + #[inline] unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - let ptr = self.as_ptr().offset(begin as isize); - let len = end - begin; - from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + (begin..end).get_unchecked(self) } #[inline] unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - let ptr = self.as_ptr().offset(begin as isize); - let len = end - begin; - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + (begin..end).get_unchecked_mut(self) } #[inline] @@ -2081,7 +2428,9 @@ impl StrExt for str { fn is_empty(&self) -> bool { self.len() == 0 } #[inline] - fn parse<T: FromStr>(&self) -> Result<T, T::Err> { FromStr::from_str(self) } + fn parse<'a, T>(&'a self) -> Result<T, T::Error> where T: TryFrom<&'a str> { + T::try_from(self) + } } #[stable(feature = "rust1", since = "1.0.0")] |
