Skip to content

Checked slicing for strings #40737

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 31, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libcollections/lib.rs
Original file line number Diff line number Diff line change
@@ -60,6 +60,7 @@
#![feature(unicode)]
#![feature(unique)]
#![feature(untagged_unions)]
#![cfg_attr(not(test), feature(str_checked_slicing))]
#![cfg_attr(test, feature(rand, test))]

#![no_std]
8 changes: 4 additions & 4 deletions src/libcollections/slice.rs
Original file line number Diff line number Diff line change
@@ -362,7 +362,7 @@ impl<T> [T] {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn get<I>(&self, index: I) -> Option<&I::Output>
where I: SliceIndex<T>
where I: SliceIndex<Self>
{
core_slice::SliceExt::get(self, index)
}
@@ -385,7 +385,7 @@ impl<T> [T] {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
where I: SliceIndex<T>
where I: SliceIndex<Self>
{
core_slice::SliceExt::get_mut(self, index)
}
@@ -405,7 +405,7 @@ impl<T> [T] {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
where I: SliceIndex<T>
where I: SliceIndex<Self>
{
core_slice::SliceExt::get_unchecked(self, index)
}
@@ -427,7 +427,7 @@ impl<T> [T] {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
where I: SliceIndex<T>
where I: SliceIndex<Self>
{
core_slice::SliceExt::get_unchecked_mut(self, index)
}
110 changes: 109 additions & 1 deletion src/libcollections/str.rs
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ use borrow::{Borrow, ToOwned};
use string::String;
use std_unicode;
use vec::Vec;
use slice::SliceConcatExt;
use slice::{SliceConcatExt, SliceIndex};
use boxed::Box;

#[stable(feature = "rust1", since = "1.0.0")]
@@ -291,6 +291,114 @@ impl str {
core_str::StrExt::as_ptr(self)
}

/// Returns a subslice of `str`.
///
/// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever
/// equivalent indexing operation would panic.
///
/// # Examples
///
/// ```
/// # #![feature(str_checked_slicing)]
/// let v = "🗻∈🌏";
/// assert_eq!(Some("🗻"), v.get(0..4));
/// assert!(v.get(1..).is_none());
/// assert!(v.get(..8).is_none());
/// assert!(v.get(..42).is_none());
/// ```
#[unstable(feature = "str_checked_slicing", issue = "39932")]
#[inline]
pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
core_str::StrExt::get(self, i)
}

/// Returns a mutable subslice of `str`.
///
/// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever
/// equivalent indexing operation would panic.
///
/// # Examples
///
/// ```
/// # #![feature(str_checked_slicing)]
/// let mut v = String::from("🗻∈🌏");
/// assert_eq!(Some("🗻"), v.get_mut(0..4).map(|v| &*v));
/// assert!(v.get_mut(1..).is_none());
/// assert!(v.get_mut(..8).is_none());
/// assert!(v.get_mut(..42).is_none());
/// ```
#[unstable(feature = "str_checked_slicing", issue = "39932")]
#[inline]
pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
core_str::StrExt::get_mut(self, i)
}

/// Returns a unchecked subslice of `str`.
///
/// This is the unchecked alternative to indexing the `str`.
///
/// # Safety
///
/// Callers of this function are responsible that these preconditions are
/// satisfied:
///
/// * The starting index must come before the ending index;
/// * Indexes must be within bounds of the original slice;
/// * Indexes must lie on UTF-8 sequence boundaries.
///
/// Failing that, the returned string slice may reference invalid memory or
/// violate the invariants communicated by the `str` type.
///
/// # Examples
///
/// ```
/// # #![feature(str_checked_slicing)]
/// let v = "🗻∈🌏";
/// unsafe {
/// assert_eq!("🗻", v.get_unchecked(0..4));
/// assert_eq!("∈", v.get_unchecked(4..7));
/// assert_eq!("🌏", v.get_unchecked(7..11));
/// }
/// ```
#[unstable(feature = "str_checked_slicing", issue = "39932")]
#[inline]
pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
core_str::StrExt::get_unchecked(self, i)
}

/// Returns a mutable, unchecked subslice of `str`.
///
/// This is the unchecked alternative to indexing the `str`.
///
/// # Safety
///
/// Callers of this function are responsible that these preconditions are
/// satisfied:
///
/// * The starting index must come before the ending index;
/// * Indexes must be within bounds of the original slice;
/// * Indexes must lie on UTF-8 sequence boundaries.
///
/// Failing that, the returned string slice may reference invalid memory or
/// violate the invariants communicated by the `str` type.
///
/// # Examples
///
/// ```
/// # #![feature(str_checked_slicing)]
/// let mut v = String::from("🗻∈🌏");
/// unsafe {
/// assert_eq!("🗻", v.get_unchecked_mut(0..4));
/// assert_eq!("∈", v.get_unchecked_mut(4..7));
/// assert_eq!("🌏", v.get_unchecked_mut(7..11));
/// }
/// ```
#[unstable(feature = "str_checked_slicing", issue = "39932")]
#[inline]
pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
core_str::StrExt::get_unchecked_mut(self, i)
}

/// Creates a string slice from another string slice, bypassing safety
/// checks.
///
52 changes: 24 additions & 28 deletions src/libcore/slice/mod.rs
Original file line number Diff line number Diff line change
@@ -97,8 +97,7 @@ pub trait SliceExt {

#[stable(feature = "core", since = "1.6.0")]
fn get<I>(&self, index: I) -> Option<&I::Output>
where I: SliceIndex<Self::Item>;

where I: SliceIndex<Self>;
#[stable(feature = "core", since = "1.6.0")]
fn first(&self) -> Option<&Self::Item>;

@@ -113,8 +112,7 @@ pub trait SliceExt {

#[stable(feature = "core", since = "1.6.0")]
unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
where I: SliceIndex<Self::Item>;

where I: SliceIndex<Self>;
#[stable(feature = "core", since = "1.6.0")]
fn as_ptr(&self) -> *const Self::Item;

@@ -141,8 +139,7 @@ pub trait SliceExt {

#[stable(feature = "core", since = "1.6.0")]
fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
where I: SliceIndex<Self::Item>;

where I: SliceIndex<Self>;
#[stable(feature = "core", since = "1.6.0")]
fn iter_mut(&mut self) -> IterMut<Self::Item>;

@@ -184,8 +181,7 @@ pub trait SliceExt {

#[stable(feature = "core", since = "1.6.0")]
unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
where I: SliceIndex<Self::Item>;

where I: SliceIndex<Self>;
#[stable(feature = "core", since = "1.6.0")]
fn as_mut_ptr(&mut self) -> *mut Self::Item;

@@ -337,7 +333,7 @@ impl<T> SliceExt for [T] {

#[inline]
fn get<I>(&self, index: I) -> Option<&I::Output>
where I: SliceIndex<T>
where I: SliceIndex<[T]>
{
index.get(self)
}
@@ -365,7 +361,7 @@ impl<T> SliceExt for [T] {

#[inline]
unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
where I: SliceIndex<T>
where I: SliceIndex<[T]>
{
index.get_unchecked(self)
}
@@ -406,7 +402,7 @@ impl<T> SliceExt for [T] {

#[inline]
fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
where I: SliceIndex<T>
where I: SliceIndex<[T]>
{
index.get_mut(self)
}
@@ -538,7 +534,7 @@ impl<T> SliceExt for [T] {

#[inline]
unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
where I: SliceIndex<T>
where I: SliceIndex<[T]>
{
index.get_unchecked_mut(self)
}
@@ -631,7 +627,7 @@ impl<T> SliceExt for [T] {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
impl<T, I> ops::Index<I> for [T]
where I: SliceIndex<T>
where I: SliceIndex<[T]>
{
type Output = I::Output;

@@ -644,7 +640,7 @@ impl<T, I> ops::Index<I> for [T]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
impl<T, I> ops::IndexMut<I> for [T]
where I: SliceIndex<T>
where I: SliceIndex<[T]>
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut I::Output {
@@ -667,37 +663,37 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! {
/// A helper trait used for indexing operations.
#[unstable(feature = "slice_get_slice", issue = "35729")]
#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
pub trait SliceIndex<T> {
pub trait SliceIndex<T: ?Sized> {
/// The output type returned by methods.
type Output: ?Sized;

/// Returns a shared reference to the output at this location, if in
/// bounds.
fn get(self, slice: &[T]) -> Option<&Self::Output>;
fn get(self, slice: &T) -> Option<&Self::Output>;

/// Returns a mutable reference to the output at this location, if in
/// bounds.
fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output>;
fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>;

/// Returns a shared reference to the output at this location, without
/// performing any bounds checking.
unsafe fn get_unchecked(self, slice: &[T]) -> &Self::Output;
unsafe fn get_unchecked(self, slice: &T) -> &Self::Output;

/// Returns a mutable reference to the output at this location, without
/// performing any bounds checking.
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut Self::Output;
unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output;

/// Returns a shared reference to the output at this location, panicking
/// if out of bounds.
fn index(self, slice: &[T]) -> &Self::Output;
fn index(self, slice: &T) -> &Self::Output;

/// Returns a mutable reference to the output at this location, panicking
/// if out of bounds.
fn index_mut(self, slice: &mut [T]) -> &mut Self::Output;
fn index_mut(self, slice: &mut T) -> &mut Self::Output;
}

#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for usize {
impl<T> SliceIndex<[T]> for usize {
type Output = T;

#[inline]
@@ -746,7 +742,7 @@ impl<T> SliceIndex<T> for usize {
}

#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for ops::Range<usize> {
impl<T> SliceIndex<[T]> for ops::Range<usize> {
type Output = [T];

#[inline]
@@ -807,7 +803,7 @@ impl<T> SliceIndex<T> for ops::Range<usize> {
}

#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for ops::RangeTo<usize> {
impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
type Output = [T];

#[inline]
@@ -842,7 +838,7 @@ impl<T> SliceIndex<T> for ops::RangeTo<usize> {
}

#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for ops::RangeFrom<usize> {
impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
type Output = [T];

#[inline]
@@ -877,7 +873,7 @@ impl<T> SliceIndex<T> for ops::RangeFrom<usize> {
}

#[stable(feature = "slice-get-slice-impls", since = "1.15.0")]
impl<T> SliceIndex<T> for ops::RangeFull {
impl<T> SliceIndex<[T]> for ops::RangeFull {
type Output = [T];

#[inline]
@@ -913,7 +909,7 @@ impl<T> SliceIndex<T> for ops::RangeFull {


#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<T> SliceIndex<T> for ops::RangeInclusive<usize> {
impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
type Output = [T];

#[inline]
@@ -976,7 +972,7 @@ impl<T> SliceIndex<T> for ops::RangeInclusive<usize> {
}

#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<T> SliceIndex<T> for ops::RangeToInclusive<usize> {
impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
type Output = [T];

#[inline]
326 changes: 303 additions & 23 deletions src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ use convert::TryFrom;
use fmt;
use iter::{Map, Cloned, FusedIterator};
use mem;
use slice;
use slice::{self, SliceIndex};

pub mod pattern;

@@ -1408,6 +1408,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.
@@ -1490,14 +1492,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)
}
}

@@ -1519,14 +1514,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)
}
}

@@ -1694,8 +1682,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)]
@@ -1745,6 +2001,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")]
@@ -1934,18 +2198,34 @@ impl StrExt for str {
LinesAny(self.lines())
}

#[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]
2 changes: 1 addition & 1 deletion src/test/compile-fail/indexing-requires-a-uint.rs
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@

fn main() {
fn bar<T>(_: T) {}
[0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<{integer}>` is not satisfied
[0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<[{integer}]>` is not satisfied

[0][0]; // should infer to be a usize

8 changes: 4 additions & 4 deletions src/test/compile-fail/integral-indexing.rs
Original file line number Diff line number Diff line change
@@ -19,8 +19,8 @@ pub fn main() {
v[3i32]; //~ERROR : std::ops::Index<i32>` is not satisfied
s.as_bytes()[3_usize];
s.as_bytes()[3];
s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex<u8>` is not satisfied
s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex<u8>` is not satisfied
s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex<u8>` is not satisfied
s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex<u8>` is not satisfied
s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
}
4 changes: 2 additions & 2 deletions src/test/compile-fail/on-unimplemented/slice-index.rs
Original file line number Diff line number Diff line change
@@ -20,10 +20,10 @@ fn main() {
let x = &[1, 2, 3] as &[i32];
x[1i32]; //~ ERROR E0277
//~| NOTE slice indices are of type `usize` or ranges of `usize`
//~| NOTE trait `std::slice::SliceIndex<i32>` is not implemented for `i32`
//~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32`
//~| NOTE required because of the requirements on the impl of `std::ops::Index<i32>`
x[..1i32]; //~ ERROR E0277
//~| NOTE slice indices are of type `usize` or ranges of `usize`
//~| NOTE trait `std::slice::SliceIndex<i32>` is not implemented for `std::ops::RangeTo<i32>`
//~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo<i32>`
//~| NOTE requirements on the impl of `std::ops::Index<std::ops::RangeTo<i32>>`
}