Skip to content
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

Checked slicing for strings #40737

Merged
merged 3 commits into from
Mar 31, 2017
Merged
Show file tree
Hide file tree
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
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 @@ -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")]
Expand Down Expand Up @@ -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.
///
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