Skip to content

Commit

Permalink
Auto merge of rust-lang#40737 - nagisa:safe-slicing-strs, r=BurntSushi
Browse files Browse the repository at this point in the history
Checked slicing for strings

cc rust-lang#39932
  • Loading branch information
bors committed Mar 31, 2017
2 parents 474f7a9 + 53a3692 commit a9329d3
Show file tree
Hide file tree
Showing 8 changed files with 448 additions and 63 deletions.
1 change: 1 addition & 0 deletions src/libcollections/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
8 changes: 4 additions & 4 deletions src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand Down
110 changes: 109 additions & 1 deletion src/libcollections/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,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")]
Expand Down Expand Up @@ -310,6 +310,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.
///
Expand Down
52 changes: 24 additions & 28 deletions src/libcore/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;

Expand All @@ -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;

Expand All @@ -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>;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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;

Expand All @@ -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 {
Expand All @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down
Loading

0 comments on commit a9329d3

Please sign in to comment.