From aac0281d30e3bf276422d215237c243047e5998b Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Mon, 11 Oct 2021 17:41:25 -0400 Subject: [PATCH] add `slice::{from_ptr_range, from_mut_ptr_range}` --- library/core/src/slice/mod.rs | 3 + library/core/src/slice/raw.rs | 111 ++++++++++++++++++++++++++++++++++ library/core/tests/lib.rs | 1 + library/core/tests/slice.rs | 22 +++++++ 4 files changed, 137 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index cd38c3a7547..7d64a88cec6 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -71,6 +71,9 @@ #[stable(feature = "from_ref", since = "1.28.0")] pub use raw::{from_mut, from_ref}; +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +pub use raw::{from_mut_ptr_range, from_ptr_range}; + // This function is public only because there is no other way to unit test heapsort. #[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] pub use sort::heapsort; diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index e7972838184..39c8d68e4bf 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -1,6 +1,7 @@ //! Free functions to create `&[T]` and `&mut [T]`. use crate::array; +use crate::ops::Range; use crate::ptr; /// Forms a slice from a pointer and a length. @@ -177,3 +178,113 @@ pub const fn from_ref(s: &T) -> &[T] { pub const fn from_mut(s: &mut T) -> &mut [T] { array::from_mut(s) } + +/// Forms a slice from a pointer range. +/// +/// This function is useful for interacting with foreign interfaces which +/// use two pointers to refer to a range of elements in memory, as is +/// common in C++. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total length of the range must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let x = [1, 2, 3]; +/// let range = x.as_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_ptr_range(range), &x); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +pub unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { + // SAFETY: the caller must uphold the safety contract for `from_ptr_range`. + unsafe { from_raw_parts(range.start, range.end.offset_from(range.start) as usize) } +} + +/// Performs the same functionality as [`from_ptr_range`], except that a +/// mutable slice is returned. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * The `start` pointer of the range must be a [valid] and properly aligned pointer +/// to the first element of a slice. +/// +/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past* +/// the last element, such that the offset from the end to the start pointer is +/// the length of the slice. +/// +/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total length of the range must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_from_ptr_range)] +/// +/// use core::slice; +/// +/// let mut x = [1, 2, 3]; +/// let range = x.as_mut_ptr_range(); +/// +/// unsafe { +/// assert_eq!(slice::from_mut_ptr_range(range), &mut [1, 2, 3]); +/// } +/// ``` +/// +/// [valid]: ptr#safety +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +pub unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] { + // SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`. + unsafe { from_raw_parts_mut(range.start, range.end.offset_from(range.start) as usize) } +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 06c7be054a0..fb59bc2596f 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -48,6 +48,7 @@ #![feature(pin_macro)] #![feature(sort_internals)] #![feature(slice_take)] +#![feature(slice_from_ptr_range)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_array_assume_init)] #![feature(maybe_uninit_write_slice)] diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 88cbd7352a2..06a30d7096c 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -2,6 +2,7 @@ use core::cmp::Ordering; use core::mem::MaybeUninit; use core::result::Result::{Err, Ok}; +use core::slice; #[test] fn test_position() { @@ -2480,3 +2481,24 @@ macro_rules! empty_max_mut { (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), } + +#[test] +fn test_slice_from_ptr_range() { + let arr = ["foo".to_owned(), "bar".to_owned()]; + let range = arr.as_ptr_range(); + unsafe { + assert_eq!(slice::from_ptr_range(range), &arr); + } + + let mut arr = [1, 2, 3]; + let range = arr.as_mut_ptr_range(); + unsafe { + assert_eq!(slice::from_mut_ptr_range(range), &mut [1, 2, 3]); + } + + let arr: [Vec; 0] = []; + let range = arr.as_ptr_range(); + unsafe { + assert_eq!(slice::from_ptr_range(range), &arr); + } +}