Rollup merge of #73986 - RalfJung:raw-slice-as-ptr, r=sfackler

add (unchecked) indexing methods to raw (and NonNull) slices

This complements the existing (unstable) `len` method. Unfortunately, for non-null slices, we cannot call this method `as_ptr` as that overlaps with the existing method of the same name.

If this looks reasonable to accept, I propose to reuse the https://github.com/rust-lang/rust/issues/71146 tracking issue and rename the feature get to `slice_ptr_methods` or so.

Cc @SimonSapin
Fixes https://github.com/rust-lang/rust/issues/60639
This commit is contained in:
Manish Goregaokar 2020-07-14 07:39:00 -07:00 committed by GitHub
commit 79894dfbac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 287 additions and 131 deletions

View File

@ -148,6 +148,7 @@
#![feature(associated_type_bounds)]
#![feature(const_type_id)]
#![feature(const_caller_location)]
#![feature(slice_ptr_get)]
#![feature(no_niche)] // rust-lang/rust#68303
#![feature(unsafe_block_in_unsafe_fn)]
#![deny(unsafe_op_in_unsafe_fn)]

View File

@ -2,6 +2,7 @@ use super::*;
use crate::cmp::Ordering::{self, Equal, Greater, Less};
use crate::intrinsics;
use crate::mem;
use crate::slice::SliceIndex;
#[lang = "const_ptr"]
impl<T: ?Sized> *const T {
@ -826,6 +827,55 @@ impl<T> *const [T] {
// Only `std` can make this guarantee.
unsafe { Repr { rust: self }.raw }.len
}
/// Returns a raw pointer to the slice's buffer.
///
/// This is equivalent to casting `self` to `*const T`, but more type-safe.
///
/// # Examples
///
/// ```rust
/// #![feature(slice_ptr_get)]
/// use std::ptr;
///
/// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3);
/// assert_eq!(slice.as_ptr(), 0 as *const i8);
/// ```
#[inline]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
pub const fn as_ptr(self) -> *const T {
self as *const T
}
/// Returns a raw pointer to an element or subslice, without doing bounds
/// checking.
///
/// Calling this method with an out-of-bounds index or when `self` is not dereferencable
/// is *[undefined behavior]* even if the resulting pointer is not used.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
///
/// ```
/// #![feature(slice_ptr_get)]
///
/// let x = &[1, 2, 4] as *const [i32];
///
/// unsafe {
/// assert_eq!(x.get_unchecked(1), x.as_ptr().add(1));
/// }
/// ```
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[inline]
pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
where
I: SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
unsafe { index.get_unchecked(self) }
}
}
// Equality for pointers

View File

@ -1,6 +1,7 @@
use super::*;
use crate::cmp::Ordering::{self, Equal, Greater, Less};
use crate::intrinsics;
use crate::slice::SliceIndex;
#[lang = "mut_ptr"]
impl<T: ?Sized> *mut T {
@ -1014,7 +1015,6 @@ impl<T> *mut [T] {
///
/// ```rust
/// #![feature(slice_ptr_len)]
///
/// use std::ptr;
///
/// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
@ -1028,6 +1028,55 @@ impl<T> *mut [T] {
// Only `std` can make this guarantee.
unsafe { Repr { rust_mut: self }.raw }.len
}
/// Returns a raw pointer to the slice's buffer.
///
/// This is equivalent to casting `self` to `*mut T`, but more type-safe.
///
/// # Examples
///
/// ```rust
/// #![feature(slice_ptr_get)]
/// use std::ptr;
///
/// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
/// assert_eq!(slice.as_mut_ptr(), 0 as *mut i8);
/// ```
#[inline]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
pub const fn as_mut_ptr(self) -> *mut T {
self as *mut T
}
/// Returns a raw pointer to an element or subslice, without doing bounds
/// checking.
///
/// Calling this method with an out-of-bounds index or when `self` is not dereferencable
/// is *[undefined behavior]* even if the resulting pointer is not used.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
///
/// ```
/// #![feature(slice_ptr_get)]
///
/// let x = &mut [1, 2, 4] as *mut [i32];
///
/// unsafe {
/// assert_eq!(x.get_unchecked_mut(1), x.as_mut_ptr().add(1));
/// }
/// ```
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[inline]
pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
where
I: SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
unsafe { index.get_unchecked_mut(self) }
}
}
// Equality for pointers

View File

@ -6,6 +6,7 @@ use crate::marker::Unsize;
use crate::mem;
use crate::ops::{CoerceUnsized, DispatchFromDyn};
use crate::ptr::Unique;
use crate::slice::SliceIndex;
/// `*mut T` but non-zero and covariant.
///
@ -192,7 +193,6 @@ impl<T> NonNull<[T]> {
///
/// ```rust
/// #![feature(slice_ptr_len, nonnull_slice_from_raw_parts)]
///
/// use std::ptr::NonNull;
///
/// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
@ -204,6 +204,57 @@ impl<T> NonNull<[T]> {
pub const fn len(self) -> usize {
self.as_ptr().len()
}
/// Returns a non-null pointer to the slice's buffer.
///
/// # Examples
///
/// ```rust
/// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
/// use std::ptr::NonNull;
///
/// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
/// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap());
/// ```
#[inline]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
pub const fn as_non_null_ptr(self) -> NonNull<T> {
// SAFETY: We know `self` is non-null.
unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) }
}
/// Returns a raw pointer to an element or subslice, without doing bounds
/// checking.
///
/// Calling this method with an out-of-bounds index or when `self` is not dereferencable
/// is *[undefined behavior]* even if the resulting pointer is not used.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
///
/// ```
/// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
/// use std::ptr::NonNull;
///
/// let x = &mut [1, 2, 4];
/// let x = NonNull::slice_from_raw_parts(NonNull::new(x.as_mut_ptr()).unwrap(), x.len());
///
/// unsafe {
/// assert_eq!(x.get_unchecked_mut(1).as_ptr(), x.as_non_null_ptr().as_ptr().add(1));
/// }
/// ```
#[unstable(feature = "slice_ptr_get", issue = "74265")]
#[inline]
pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
where
I: SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
// As a consequence, the resulting pointer cannot be NULL.
unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) }
}
}
#[stable(feature = "nonnull", since = "1.25.0")]

View File

@ -310,8 +310,10 @@ impl<T> [T] {
where
I: SliceIndex<Self>,
{
// SAFETY: the caller must uphold the safety requirements for `get_unchecked`.
unsafe { index.get_unchecked(self) }
// SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
// the slice is dereferencable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &*index.get_unchecked(self) }
}
/// Returns a mutable reference to an element or subslice, without doing
@ -342,8 +344,10 @@ impl<T> [T] {
where
I: SliceIndex<Self>,
{
// SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`.
unsafe { index.get_unchecked_mut(self) }
// SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
// the slice is dereferencable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &mut *index.get_unchecked_mut(self) }
}
/// Returns a raw pointer to the slice's buffer.
@ -3010,6 +3014,9 @@ mod private_slice_index {
}
/// A helper trait used for indexing operations.
///
/// Implementations of this trait have to promise that if the argument
/// to `get_(mut_)unchecked` is a safe reference, then so is the result.
#[stable(feature = "slice_get_slice", since = "1.28.0")]
#[rustc_on_unimplemented(
on(T = "str", label = "string indices are ranges of `usize`",),
@ -3021,7 +3028,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
message = "the type `{T}` cannot be indexed by `{Self}`",
label = "slice indices are of type `usize` or ranges of `usize`"
)]
pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
/// The output type returned by methods.
#[stable(feature = "slice_get_slice", since = "1.28.0")]
type Output: ?Sized;
@ -3038,21 +3045,21 @@ pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
/// Returns a shared reference to the output at this location, without
/// performing any bounds checking.
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
/// even if the resulting reference is not used.
/// Calling this method with an out-of-bounds index or a dangling `slice` pointer
/// is *[undefined behavior]* even if the resulting reference is not used.
///
/// [undefined behavior]: ../../reference/behavior-considered-undefined.html
#[unstable(feature = "slice_index_methods", issue = "none")]
unsafe fn get_unchecked(self, slice: &T) -> &Self::Output;
unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
/// Returns a mutable reference to the output at this location, without
/// performing any bounds checking.
/// Calling this method with an out-of-bounds index is *[undefined behavior]*
/// even if the resulting reference is not used.
/// Calling this method with an out-of-bounds index or a dangling `slice` pointer
/// is *[undefined behavior]* even if the resulting reference is not used.
///
/// [undefined behavior]: ../../reference/behavior-considered-undefined.html
#[unstable(feature = "slice_index_methods", issue = "none")]
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.
@ -3068,33 +3075,32 @@ pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
}
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
impl<T> SliceIndex<[T]> for usize {
unsafe impl<T> SliceIndex<[T]> for usize {
type Output = T;
#[inline]
fn get(self, slice: &[T]) -> Option<&T> {
if self < slice.len() { unsafe { Some(self.get_unchecked(slice)) } } else { None }
if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
}
#[inline]
fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
if self < slice.len() { unsafe { Some(self.get_unchecked_mut(slice)) } } else { None }
if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None }
}
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &T {
// SAFETY: `slice` cannot be longer than `isize::MAX` and
// the caller guarantees that `self` is in bounds of `slice`
// so `self` cannot overflow an `isize`, so the call to `add` is safe.
// The obtained pointer comes from a reference which is guaranteed
// to be valid.
unsafe { &*slice.as_ptr().add(self) }
unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
// SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
// so the call to `add` is safe.
unsafe { slice.as_ptr().add(self) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut T {
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
// SAFETY: see comments for `get_unchecked` above.
unsafe { &mut *slice.as_mut_ptr().add(self) }
unsafe { slice.as_mut_ptr().add(self) }
}
#[inline]
@ -3111,7 +3117,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> {
unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
type Output = [T];
#[inline]
@ -3119,7 +3125,7 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
if self.start > self.end || self.end > slice.len() {
None
} else {
unsafe { Some(self.get_unchecked(slice)) }
unsafe { Some(&*self.get_unchecked(slice)) }
}
}
@ -3128,24 +3134,25 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
if self.start > self.end || self.end > slice.len() {
None
} else {
unsafe { Some(self.get_unchecked_mut(slice)) }
unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
}
}
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
// SAFETY: `slice` cannot be longer than `isize::MAX` and
// the caller guarantees that `self` is in bounds of `slice`
// so `self` cannot overflow an `isize`, so the call to `add` is safe.
// Also, since the caller guarantees that `self` is in bounds of `slice`,
// `from_raw_parts` will give a subslice of `slice` which is always safe.
unsafe { from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
// SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
// so the call to `add` is safe.
unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
// SAFETY: see comments for `get_unchecked` above.
unsafe { from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) }
unsafe {
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
}
}
#[inline]
@ -3155,7 +3162,7 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
} else if self.end > slice.len() {
slice_index_len_fail(self.end, slice.len());
}
unsafe { self.get_unchecked(slice) }
unsafe { &*self.get_unchecked(slice) }
}
#[inline]
@ -3165,12 +3172,12 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
} else if self.end > slice.len() {
slice_index_len_fail(self.end, slice.len());
}
unsafe { self.get_unchecked_mut(slice) }
unsafe { &mut *self.get_unchecked_mut(slice) }
}
}
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
type Output = [T];
#[inline]
@ -3184,13 +3191,13 @@ impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
}
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
unsafe { (0..self.end).get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
unsafe { (0..self.end).get_unchecked_mut(slice) }
}
@ -3207,7 +3214,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> {
unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
type Output = [T];
#[inline]
@ -3221,13 +3228,13 @@ impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
}
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
unsafe { (self.start..slice.len()).get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
unsafe { (self.start..slice.len()).get_unchecked_mut(slice) }
}
@ -3244,7 +3251,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 {
unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
type Output = [T];
#[inline]
@ -3258,12 +3265,12 @@ impl<T> SliceIndex<[T]> for ops::RangeFull {
}
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
slice
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
slice
}
@ -3279,7 +3286,7 @@ impl<T> SliceIndex<[T]> for ops::RangeFull {
}
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
type Output = [T];
#[inline]
@ -3297,13 +3304,13 @@ impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
}
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
}
@ -3326,7 +3333,7 @@ impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
}
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
type Output = [T];
#[inline]
@ -3340,13 +3347,13 @@ impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
}
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
unsafe { (0..=self.end).get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
unsafe { (0..=self.end).get_unchecked_mut(slice) }
}

View File

@ -1731,7 +1731,8 @@ Section: Trait implementations
mod traits {
use crate::cmp::Ordering;
use crate::ops;
use crate::slice::{self, SliceIndex};
use crate::ptr;
use crate::slice::SliceIndex;
/// Implements ordering of strings.
///
@ -1822,7 +1823,7 @@ mod traits {
///
/// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::RangeFull {
unsafe impl SliceIndex<str> for ops::RangeFull {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
@ -1833,11 +1834,11 @@ mod traits {
Some(slice)
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
slice
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
slice
}
#[inline]
@ -1886,7 +1887,7 @@ mod traits {
/// // &s[3 .. 100];
/// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::Range<usize> {
unsafe impl SliceIndex<str> for ops::Range<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
@ -1894,8 +1895,10 @@ mod traits {
&& slice.is_char_boundary(self.start)
&& slice.is_char_boundary(self.end)
{
// SAFETY: just checked that `start` and `end` are on a char boundary.
Some(unsafe { self.get_unchecked(slice) })
// SAFETY: just checked that `start` and `end` are on a char boundary,
// and we are passing in a safe reference, so the return value will also be one.
// We also checked char boundaries, so this is valid UTF-8.
Some(unsafe { &*self.get_unchecked(slice) })
} else {
None
}
@ -1907,34 +1910,28 @@ mod traits {
&& slice.is_char_boundary(self.end)
{
// SAFETY: just checked that `start` and `end` are on a char boundary.
Some(unsafe { self.get_unchecked_mut(slice) })
// We know the pointer is unique because we got it from `slice`.
Some(unsafe { &mut *self.get_unchecked_mut(slice) })
} else {
None
}
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
let slice = slice as *const [u8];
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
// which satisfies all the conditions for `add`.
let ptr = unsafe { slice.as_ptr().add(self.start) };
let len = self.end - self.start;
// SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
// we can safely construct a subslice with `from_raw_parts` and use it
// since we return a shared thus immutable reference.
// The call to `from_utf8_unchecked` is safe since the data comes from
// a `str` which is guaranteed to be valid utf8, since the caller
// must guarantee that `self.start` and `self.end` are char boundaries.
unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
ptr::slice_from_raw_parts(ptr, len) as *const str
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
let slice = slice as *mut [u8];
// SAFETY: see comments for `get_unchecked`.
let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
let len = self.end - self.start;
// SAFETY: mostly identical to the comments for `get_unchecked`, except that we
// can return a mutable reference since the caller passed a mutable reference
// and is thus guaranteed to have exclusive write access to `slice`.
unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
@ -1949,8 +1946,9 @@ mod traits {
&& slice.is_char_boundary(self.start)
&& slice.is_char_boundary(self.end)
{
// SAFETY: just checked that `start` and `end` are on a char boundary.
unsafe { self.get_unchecked_mut(slice) }
// SAFETY: just checked that `start` and `end` are on a char boundary,
// and we are passing in a safe reference, so the return value will also be one.
unsafe { &mut *self.get_unchecked_mut(slice) }
} else {
super::slice_error_fail(slice, self.start, self.end)
}
@ -1973,13 +1971,14 @@ mod traits {
/// Panics if `end` does not point to the starting byte offset of a
/// character (as defined by `is_char_boundary`), or if `end > len`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::RangeTo<usize> {
unsafe 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) {
// SAFETY: just checked that `end` is on a char boundary.
Some(unsafe { self.get_unchecked(slice) })
// SAFETY: just checked that `end` is on a char boundary,
// and we are passing in a safe reference, so the return value will also be one.
Some(unsafe { &*self.get_unchecked(slice) })
} else {
None
}
@ -1987,30 +1986,24 @@ mod traits {
#[inline]
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
if slice.is_char_boundary(self.end) {
// SAFETY: just checked that `end` is on a char boundary.
Some(unsafe { self.get_unchecked_mut(slice) })
// SAFETY: just checked that `end` is on a char boundary,
// and we are passing in a safe reference, so the return value will also be one.
Some(unsafe { &mut *self.get_unchecked_mut(slice) })
} else {
None
}
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
let slice = slice as *const [u8];
let ptr = slice.as_ptr();
// SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
// we can safely construct a subslice with `from_raw_parts` and use it
// since we return a shared thus immutable reference.
// The call to `from_utf8_unchecked` is safe since the data comes from
// a `str` which is guaranteed to be valid utf8, since the caller
// must guarantee that `self.end` is a char boundary.
unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) }
ptr::slice_from_raw_parts(ptr, self.end) as *const str
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
let slice = slice as *mut [u8];
let ptr = slice.as_mut_ptr();
// SAFETY: mostly identical to `get_unchecked`, except that we can safely
// return a mutable reference since the caller passed a mutable reference
// and is thus guaranteed to have exclusive write access to `slice`.
unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) }
ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
@ -2020,8 +2013,9 @@ mod traits {
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
if slice.is_char_boundary(self.end) {
// SAFETY: just checked that `end` is on a char boundary.
unsafe { self.get_unchecked_mut(slice) }
// SAFETY: just checked that `end` is on a char boundary,
// and we are passing in a safe reference, so the return value will also be one.
unsafe { &mut *self.get_unchecked_mut(slice) }
} else {
super::slice_error_fail(slice, 0, self.end)
}
@ -2045,13 +2039,14 @@ mod traits {
/// Panics if `begin` does not point to the starting byte offset of
/// a character (as defined by `is_char_boundary`), or if `begin >= len`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::RangeFrom<usize> {
unsafe 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) {
// SAFETY: just checked that `start` is on a char boundary.
Some(unsafe { self.get_unchecked(slice) })
// SAFETY: just checked that `start` is on a char boundary,
// and we are passing in a safe reference, so the return value will also be one.
Some(unsafe { &*self.get_unchecked(slice) })
} else {
None
}
@ -2059,35 +2054,29 @@ mod traits {
#[inline]
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
if slice.is_char_boundary(self.start) {
// SAFETY: just checked that `start` is on a char boundary.
Some(unsafe { self.get_unchecked_mut(slice) })
// SAFETY: just checked that `start` is on a char boundary,
// and we are passing in a safe reference, so the return value will also be one.
Some(unsafe { &mut *self.get_unchecked_mut(slice) })
} else {
None
}
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
let slice = slice as *const [u8];
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
// which satisfies all the conditions for `add`.
let ptr = unsafe { slice.as_ptr().add(self.start) };
let len = slice.len() - self.start;
// SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
// we can safely construct a subslice with `from_raw_parts` and use it
// since we return a shared thus immutable reference.
// The call to `from_utf8_unchecked` is safe since the data comes from
// a `str` which is guaranteed to be valid utf8, since the caller
// must guarantee that `self.start` is a char boundary.
unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
ptr::slice_from_raw_parts(ptr, len) as *const str
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
let slice = slice as *mut [u8];
// SAFETY: identical to `get_unchecked`.
let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
let len = slice.len() - self.start;
// SAFETY: mostly identical to `get_unchecked`, except that we can safely
// return a mutable reference since the caller passed a mutable reference
// and is thus guaranteed to have exclusive write access to `slice`.
unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
@ -2097,8 +2086,9 @@ mod traits {
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
if slice.is_char_boundary(self.start) {
// SAFETY: just checked that `start` is on a char boundary.
unsafe { self.get_unchecked_mut(slice) }
// SAFETY: just checked that `start` is on a char boundary,
// and we are passing in a safe reference, so the return value will also be one.
unsafe { &mut *self.get_unchecked_mut(slice) }
} else {
super::slice_error_fail(slice, self.start, slice.len())
}
@ -2122,7 +2112,7 @@ mod traits {
/// to the ending byte offset of a character (`end + 1` is either a starting
/// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl SliceIndex<str> for ops::RangeInclusive<usize> {
unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
@ -2141,12 +2131,12 @@ mod traits {
}
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
}
@ -2181,7 +2171,7 @@ mod traits {
/// (`end + 1` is either a starting byte offset as defined by
/// `is_char_boundary`, or equal to `len`), or if `end >= len`.
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl SliceIndex<str> for ops::RangeToInclusive<usize> {
unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
@ -2192,12 +2182,12 @@ mod traits {
if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) }
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
unsafe { (..self.end + 1).get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
unsafe { (..self.end + 1).get_unchecked_mut(slice) }
}
@ -2560,8 +2550,10 @@ impl str {
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[inline]
pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
unsafe { i.get_unchecked(self) }
// SAFETY: the caller must uphold the safety contract for `get_unchecked`;
// the slice is dereferencable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &*i.get_unchecked(self) }
}
/// Returns a mutable, unchecked subslice of `str`.
@ -2593,8 +2585,10 @@ impl str {
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[inline]
pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
unsafe { i.get_unchecked_mut(self) }
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
// the slice is dereferencable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &mut *i.get_unchecked_mut(self) }
}
/// Creates a string slice from another string slice, bypassing safety
@ -2644,8 +2638,10 @@ impl str {
#[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")]
#[inline]
pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
unsafe { (begin..end).get_unchecked(self) }
// SAFETY: the caller must uphold the safety contract for `get_unchecked`;
// the slice is dereferencable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &*(begin..end).get_unchecked(self) }
}
/// Creates a string slice from another string slice, bypassing safety
@ -2676,8 +2672,10 @@ impl str {
#[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")]
#[inline]
pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
unsafe { (begin..end).get_unchecked_mut(self) }
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
// the slice is dereferencable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &mut *(begin..end).get_unchecked_mut(self) }
}
/// Divide one string slice into two at an index.