Skip to content

Commit

Permalink
Rollup merge of rust-lang#73986 - RalfJung:raw-slice-as-ptr, r=sfackler
Browse files Browse the repository at this point in the history
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 rust-lang#71146 tracking issue and rename the feature get to `slice_ptr_methods` or so.

Cc @SimonSapin
Fixes rust-lang#60639
  • Loading branch information
Manishearth authored Jul 13, 2020
2 parents cb0d9e8 + ff5e107 commit e28e2f6
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 131 deletions.
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
50 changes: 50 additions & 0 deletions src/libcore/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
51 changes: 50 additions & 1 deletion src/libcore/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down
53 changes: 52 additions & 1 deletion src/libcore/ptr/non_null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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);
Expand All @@ -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")]
Expand Down
Loading

0 comments on commit e28e2f6

Please sign in to comment.