]> git.lizzy.rs Git - rust.git/commitdiff
add `slice::{from_ptr_range, from_mut_ptr_range}`
authorIbraheem Ahmed <ibrah1440@gmail.com>
Mon, 11 Oct 2021 21:41:25 +0000 (17:41 -0400)
committerIbraheem Ahmed <ibraheem@ibraheem.ca>
Sun, 27 Feb 2022 21:53:26 +0000 (16:53 -0500)
library/core/src/slice/mod.rs
library/core/src/slice/raw.rs
library/core/tests/lib.rs
library/core/tests/slice.rs

index cd38c3a75473d4c1393823bb1afab8ef61812654..7d64a88cec67a8235c36ba7f42b54c6120ae94f1 100644 (file)
@@ -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;
index e7972838184815eccbb039bf6504838f454c5348..39c8d68e4bf343dbfec4e20f9143b1b4bfd625b1 100644 (file)
@@ -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<T>(s: &T) -> &[T] {
 pub const fn from_mut<T>(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) }
+}
index 06c7be054a0381b0eaa9574efba3277999d4fe46..fb59bc2596f76435043bf6cfbdcd3c9ba9f1b8dc 100644 (file)
@@ -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)]
index 88cbd7352a2141b59341f41ffe4ee3b727c39e18..06a30d7096c775d4ef306f7d89fbcbd6ae5274d7 100644 (file)
@@ -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<String>; 0] = [];
+    let range = arr.as_ptr_range();
+    unsafe {
+        assert_eq!(slice::from_ptr_range(range), &arr);
+    }
+}