From 4936f96d42eeaa65e4b169113796f29c8c769f39 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 25 Oct 2019 14:07:08 +0200 Subject: [PATCH 1/4] Add [T]::as_ptr_range() and [T]::as_mut_ptr_range(). See https://github.com/rust-lang/rfcs/pull/2791 for motivation. --- src/libcore/slice/mod.rs | 61 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 4e79ea812044b..0770b0c6f9016 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -28,7 +28,7 @@ use crate::fmt; use crate::intrinsics::{assume, exact_div, unchecked_sub, is_aligned_and_not_null}; use crate::isize; use crate::iter::*; -use crate::ops::{FnMut, self}; +use crate::ops::{FnMut, Range, self}; use crate::option::Option; use crate::option::Option::{None, Some}; use crate::result::Result; @@ -407,6 +407,65 @@ impl [T] { self as *mut [T] as *mut T } + /// Returns the two raw pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the size. + /// + /// See [`as_ptr`] for warnings on using these pointers. The end pointer + /// requires extra caution, as it does not point to a valid element in the + /// slice. + /// + /// 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++. + /// + /// It can also be useful to check if a reference or pointer to an element + /// refers to an element of this slice: + /// + /// ``` + /// let a = [1,2,3]; + /// let x = &a[1]; + /// let y = &5; + /// assert!(a.as_ptr_range().contains(x)); + /// assert!(!a.as_ptr_range().contains(y)); + /// ``` + /// + /// [`as_ptr`]: #method.as_ptr + #[unstable(feature = "slice_ptr_range", issue = "0")] + #[inline] + pub fn as_ptr_range(&self) -> Range<*const T> { + let start = self.as_ptr(); + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Returns the two unsafe mutable pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the size. + /// + /// See [`as_mut_ptr`] for warnings on using these pointers. The end + /// pointer requires extra caution, as it does not point to a valid element + /// in the slice. + /// + /// 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++. + /// + /// [`as_mut_ptr`]: #method.as_mut_ptr + #[unstable(feature = "slice_ptr_range", issue = "0")] + #[inline] + pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + let start = self.as_mut_ptr(); + let end = unsafe { start.add(self.len()) }; + start..end + } + /// Swaps two elements in the slice. /// /// # Arguments From f1b69b0a871a5d78504c0dc197e0ebb477de653c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 25 Oct 2019 14:33:07 +0200 Subject: [PATCH 2/4] Add slice_ptr_range tracking issue number. --- src/libcore/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0770b0c6f9016..0a115ce84caad 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -434,7 +434,7 @@ impl [T] { /// ``` /// /// [`as_ptr`]: #method.as_ptr - #[unstable(feature = "slice_ptr_range", issue = "0")] + #[unstable(feature = "slice_ptr_range", issue = "65807")] #[inline] pub fn as_ptr_range(&self) -> Range<*const T> { let start = self.as_ptr(); @@ -458,7 +458,7 @@ impl [T] { /// common in C++. /// /// [`as_mut_ptr`]: #method.as_mut_ptr - #[unstable(feature = "slice_ptr_range", issue = "0")] + #[unstable(feature = "slice_ptr_range", issue = "65807")] #[inline] pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> { let start = self.as_mut_ptr(); From de9b660a40728d4c4213f2ec7a1c99a9bc352023 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 25 Oct 2019 15:21:00 +0200 Subject: [PATCH 3/4] Explain why pointer::add in slice::as_ptr_range is safe. --- src/libcore/slice/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0a115ce84caad..185913a47f1a2 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -437,6 +437,23 @@ impl [T] { #[unstable(feature = "slice_ptr_range", issue = "65807")] #[inline] pub fn as_ptr_range(&self) -> Range<*const T> { + // The `add` here is safe, because: + // + // - Both pointers are part of the same object, as pointing directly + // past the object also counts. + // + // - The size of the slice is never larger than isize::MAX bytes, as + // noted here: + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/102#issuecomment-473340447 + // - https://doc.rust-lang.org/reference/behavior-considered-undefined.html + // - https://doc.rust-lang.org/core/slice/fn.from_raw_parts.html#safety + // (This doesn't seem normative yet, but the very same assumption is + // made in many places, including the Index implementation of slices.) + // + // - There is no wrapping around involved, as slices do not wrap past + // the end of the address space. + // + // See the documentation of pointer::add. let start = self.as_ptr(); let end = unsafe { start.add(self.len()) }; start..end @@ -461,6 +478,7 @@ impl [T] { #[unstable(feature = "slice_ptr_range", issue = "65807")] #[inline] pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + // See as_ptr_range() above for why `add` here is safe. let start = self.as_mut_ptr(); let end = unsafe { start.add(self.len()) }; start..end From 225b2453077faf6d02d72fb0b7b03ad57b5b390a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 25 Oct 2019 17:22:03 +0200 Subject: [PATCH 4/4] Fix slice::as_ptr_range doctest. --- src/libcore/slice/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 185913a47f1a2..8e7c3296f9584 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -426,9 +426,12 @@ impl [T] { /// refers to an element of this slice: /// /// ``` - /// let a = [1,2,3]; + /// #![feature(slice_ptr_range)] + /// + /// let a = [1, 2, 3]; /// let x = &a[1]; /// let y = &5; + /// /// assert!(a.as_ptr_range().contains(x)); /// assert!(!a.as_ptr_range().contains(y)); /// ```