From 2f0dd63bbe83938b9eda5b6076543d420bae2f2b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 18:36:43 +0200 Subject: [PATCH 1/3] Checked (and unchecked) slicing for strings? MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What is this magicβ€½ --- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 8 +- src/libcollections/str.rs | 110 +++++++++++- src/libcore/slice/mod.rs | 52 +++--- src/libcore/str/mod.rs | 326 +++++++++++++++++++++++++++++++++--- 5 files changed, 441 insertions(+), 56 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 72e950bc91fa9..00448b6abb2cf 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -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] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 5233887620a91..424e175996ec8 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -362,7 +362,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get(self, index) } @@ -385,7 +385,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_mut(self, index) } @@ -405,7 +405,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_unchecked(self, index) } @@ -427,7 +427,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_unchecked_mut(self, index) } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 90e54a383d623..84b73090817d2 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -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 = "0")] + #[inline] + pub fn get>(&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 = "0")] + #[inline] + pub fn get_mut>(&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 = "0")] + #[inline] + pub unsafe fn get_unchecked>(&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 = "0")] + #[inline] + pub unsafe fn get_unchecked_mut>(&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. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6f8b199f886b7..4e56fa80cd9ca 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -97,8 +97,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex; - + where I: SliceIndex; #[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(&self, index: I) -> &I::Output - where I: SliceIndex; - + where I: SliceIndex; #[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(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn iter_mut(&mut self) -> IterMut; @@ -184,8 +181,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn as_mut_ptr(&mut self) -> *mut Self::Item; @@ -337,7 +333,7 @@ impl SliceExt for [T] { #[inline] fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex + where I: SliceIndex<[T]> { index.get(self) } @@ -365,7 +361,7 @@ impl SliceExt for [T] { #[inline] unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_unchecked(self) } @@ -406,7 +402,7 @@ impl SliceExt for [T] { #[inline] fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_mut(self) } @@ -538,7 +534,7 @@ impl SliceExt for [T] { #[inline] unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_unchecked_mut(self) } @@ -631,7 +627,7 @@ impl SliceExt for [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] impl ops::Index for [T] - where I: SliceIndex + where I: SliceIndex<[T]> { type Output = I::Output; @@ -644,7 +640,7 @@ impl ops::Index for [T] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut for [T] - where I: SliceIndex + 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 { +pub trait SliceIndex { /// 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 SliceIndex for usize { +impl SliceIndex<[T]> for usize { type Output = T; #[inline] @@ -746,7 +742,7 @@ impl SliceIndex for usize { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::Range { +impl SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -807,7 +803,7 @@ impl SliceIndex for ops::Range { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeTo { +impl SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -842,7 +838,7 @@ impl SliceIndex for ops::RangeTo { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeFrom { +impl SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -877,7 +873,7 @@ impl SliceIndex for ops::RangeFrom { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeFull { +impl SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -913,7 +909,7 @@ impl SliceIndex for ops::RangeFull { #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl SliceIndex for ops::RangeInclusive { +impl SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -976,7 +972,7 @@ impl SliceIndex for ops::RangeInclusive { } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl SliceIndex for ops::RangeToInclusive { +impl SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index cf3e8a684dfab..aecfaa7ee023b 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -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) -> &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> for str { #[inline] fn index_mut(&mut self, index: ops::Range) -> &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 = "0")] + impl SliceIndex 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 = "0")] + impl SliceIndex for ops::Range { + 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 = "0")] + impl SliceIndex for ops::RangeTo { + 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 = "0")] + impl SliceIndex for ops::RangeFrom { + 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 = "0")] + impl SliceIndex for ops::RangeInclusive { + 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 = "0")] + impl SliceIndex for ops::RangeToInclusive { + 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 = "0")] + fn get>(&self, i: I) -> Option<&I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "0")] + fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "0")] + unsafe fn get_unchecked>(&self, i: I) -> &I::Output; + #[unstable(feature = "str_checked_slicing", issue = "0")] + unsafe fn get_unchecked_mut>(&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>(&self, i: I) -> Option<&I::Output> { + i.get(self) + } + + #[inline] + fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + i.get_mut(self) + } + + #[inline] + unsafe fn get_unchecked>(&self, i: I) -> &I::Output { + i.get_unchecked(self) + } + + #[inline] + unsafe fn get_unchecked_mut>(&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] From 99e4c0ad8b0c2e551e7ef0db60b8a2b84f35c1ee Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 18:39:41 +0200 Subject: [PATCH 2/3] Tracking issue numbers --- src/libcollections/str.rs | 8 ++++---- src/libcore/str/mod.rs | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 84b73090817d2..4fe2b826c96f5 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -306,7 +306,7 @@ impl str { /// assert!(v.get(..8).is_none()); /// assert!(v.get(..42).is_none()); /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub fn get>(&self, i: I) -> Option<&I::Output> { core_str::StrExt::get(self, i) @@ -327,7 +327,7 @@ impl str { /// assert!(v.get_mut(..8).is_none()); /// assert!(v.get_mut(..42).is_none()); /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { core_str::StrExt::get_mut(self, i) @@ -360,7 +360,7 @@ impl str { /// assert_eq!("🌏", v.get_unchecked(7..11)); /// } /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { core_str::StrExt::get_unchecked(self, i) @@ -393,7 +393,7 @@ impl str { /// assert_eq!("🌏", v.get_unchecked_mut(7..11)); /// } /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { core_str::StrExt::get_unchecked_mut(self, i) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index aecfaa7ee023b..b6c421ecd3201 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1683,7 +1683,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeFull { type Output = str; #[inline] @@ -1712,7 +1712,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::Range { type Output = str; #[inline] @@ -1766,7 +1766,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeTo { type Output = str; #[inline] @@ -1810,7 +1810,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeFrom { type Output = str; #[inline] @@ -1856,7 +1856,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeInclusive { type Output = str; #[inline] @@ -1905,7 +1905,7 @@ mod traits { - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] @@ -2001,13 +2001,13 @@ 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 = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] fn get>(&self, i: I) -> Option<&I::Output>; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] unsafe fn get_unchecked>(&self, i: I) -> &I::Output; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output; #[stable(feature = "core", since = "1.6.0")] unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str; From 53a36923f12d6c9b7ef9cb0fe73cda50385b1f70 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 22:02:42 +0200 Subject: [PATCH 3/3] Fix the tests --- src/test/compile-fail/indexing-requires-a-uint.rs | 2 +- src/test/compile-fail/integral-indexing.rs | 8 ++++---- src/test/compile-fail/on-unimplemented/slice-index.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/compile-fail/indexing-requires-a-uint.rs b/src/test/compile-fail/indexing-requires-a-uint.rs index 1889d76c03c03..624944f7344cb 100644 --- a/src/test/compile-fail/indexing-requires-a-uint.rs +++ b/src/test/compile-fail/indexing-requires-a-uint.rs @@ -13,7 +13,7 @@ fn main() { fn bar(_: 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 diff --git a/src/test/compile-fail/integral-indexing.rs b/src/test/compile-fail/integral-indexing.rs index 1815d0e978a94..659b08b55a00a 100644 --- a/src/test/compile-fail/integral-indexing.rs +++ b/src/test/compile-fail/integral-indexing.rs @@ -19,8 +19,8 @@ pub fn main() { v[3i32]; //~ERROR : std::ops::Index` is not satisfied s.as_bytes()[3_usize]; s.as_bytes()[3]; - s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex` 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 } diff --git a/src/test/compile-fail/on-unimplemented/slice-index.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs index d28b823ddc145..1a9ed2dd6e4dc 100644 --- a/src/test/compile-fail/on-unimplemented/slice-index.rs +++ b/src/test/compile-fail/on-unimplemented/slice-index.rs @@ -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` 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` x[..1i32]; //~ ERROR E0277 //~| NOTE slice indices are of type `usize` or ranges of `usize` - //~| NOTE trait `std::slice::SliceIndex` is not implemented for `std::ops::RangeTo` + //~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo` //~| NOTE requirements on the impl of `std::ops::Index>` }