]> git.lizzy.rs Git - rust.git/blobdiff - library/core/src/ptr/mut_ptr.rs
stabilize ptr_offset_from
[rust.git] / library / core / src / ptr / mut_ptr.rs
index 811e58875d5bb3033333f2e8b2de65811698da32..f4b28290f3274a26eb6dc9476d226b79d4ba956d 100644 (file)
@@ -1,7 +1,7 @@
 use super::*;
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::intrinsics;
-use crate::slice::SliceIndex;
+use crate::slice::{self, SliceIndex};
 
 #[lang = "mut_ptr"]
 impl<T: ?Sized> *mut T {
@@ -47,32 +47,36 @@ pub const fn cast<U>(self) -> *mut U {
         self as _
     }
 
-    /// Returns `None` if the pointer is null, or else returns a reference to
-    /// the value wrapped in `Some`.
+    /// Returns `None` if the pointer is null, or else returns a shared reference to
+    /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
+    /// must be used instead.
     ///
-    /// # Safety
+    /// For the mutable counterpart see [`as_mut`].
+    ///
+    /// [`as_uninit_ref`]: #method.as_uninit_ref-1
+    /// [`as_mut`]: #method.as_mut
     ///
-    /// While this method and its mutable counterpart are useful for
-    /// null-safety, it is important to note that this is still an unsafe
-    /// operation because the returned value could be pointing to invalid
-    /// memory.
+    /// # Safety
     ///
     /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
     /// all of the following is true:
-    /// - it is properly aligned
-    /// - it must point to an initialized instance of T; in particular, the pointer must be
-    ///   "dereferencable" in the sense defined [here].
+    ///
+    /// * The pointer must be properly aligned.
+    ///
+    /// * It must be "dereferencable" in the sense defined in [the module documentation].
+    ///
+    /// * The pointer must point to an initialized instance of `T`.
+    ///
+    /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+    ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
     /// (The part about being initialized is not yet fully decided, but until
     /// it is, the only safe approach is to ensure that they are indeed initialized.)
     ///
-    /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
-    /// not necessarily reflect the actual lifetime of the data. *You* must enforce
-    /// Rust's aliasing rules. In particular, for the duration of this lifetime,
-    /// the memory the pointer points to must not get mutated (except inside `UnsafeCell`).
-    ///
-    /// [here]: crate::ptr#safety
+    /// [the module documentation]: crate::ptr#safety
     ///
     /// # Examples
     ///
@@ -110,6 +114,59 @@ pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
         if self.is_null() { None } else { unsafe { Some(&*self) } }
     }
 
+    /// Returns `None` if the pointer is null, or else returns a shared reference to
+    /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
+    /// that the value has to be initialized.
+    ///
+    /// For the mutable counterpart see [`as_uninit_mut`].
+    ///
+    /// [`as_ref`]: #method.as_ref-1
+    /// [`as_uninit_mut`]: #method.as_uninit_mut
+    ///
+    /// # Safety
+    ///
+    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// all of the following is true:
+    ///
+    /// * The pointer must be properly aligned.
+    ///
+    /// * It must be "dereferencable" in the sense defined in [the module documentation].
+    ///
+    /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+    ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   not get mutated (except inside `UnsafeCell`).
+    ///
+    /// This applies even if the result of this method is unused!
+    ///
+    /// [the module documentation]: crate::ptr#safety
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(ptr_as_uninit)]
+    ///
+    /// let ptr: *mut u8 = &mut 10u8 as *mut u8;
+    ///
+    /// unsafe {
+    ///     if let Some(val_back) = ptr.as_uninit_ref() {
+    ///         println!("We got back the value: {}!", val_back.assume_init());
+    ///     }
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "ptr_as_uninit", issue = "75402")]
+    pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
+    where
+        T: Sized,
+    {
+        // SAFETY: the caller must guarantee that `self` meets all the
+        // requirements for a reference.
+        if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
+    }
+
     /// Calculates the offset from a pointer.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
@@ -235,33 +292,36 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T
         unsafe { intrinsics::arith_offset(self, count) as *mut T }
     }
 
-    /// Returns `None` if the pointer is null, or else returns a mutable
-    /// reference to the value wrapped in `Some`.
+    /// Returns `None` if the pointer is null, or else returns a unique reference to
+    /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`]
+    /// must be used instead.
     ///
-    /// # Safety
+    /// For the shared counterpart see [`as_ref`].
     ///
-    /// As with [`as_ref`], this is unsafe because it cannot verify the validity
-    /// of the returned pointer, nor can it ensure that the lifetime `'a`
-    /// returned is indeed a valid lifetime for the contained data.
+    /// [`as_uninit_mut`]: #method.as_uninit_mut
+    /// [`as_ref`]: #method.as_ref-1
+    ///
+    /// # Safety
     ///
     /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
     /// all of the following is true:
-    /// - it is properly aligned
-    /// - it must point to an initialized instance of T; in particular, the pointer must be
-    ///   "dereferenceable" in the sense defined [here].
+    ///
+    /// * The pointer must be properly aligned.
+    ///
+    /// * It must be "dereferencable" in the sense defined in [the module documentation].
+    ///
+    /// * The pointer must point to an initialized instance of `T`.
+    ///
+    /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+    ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   not get accessed (read or written) through any other pointer.
     ///
     /// This applies even if the result of this method is unused!
     /// (The part about being initialized is not yet fully decided, but until
-    /// it is the only safe approach is to ensure that they are indeed initialized.)
-    ///
-    /// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
-    /// not necessarily reflect the actual lifetime of the data. *You* must enforce
-    /// Rust's aliasing rules. In particular, for the duration of this lifetime,
-    /// the memory this pointer points to must not get accessed (read or written)
-    /// through any other pointer.
+    /// it is, the only safe approach is to ensure that they are indeed initialized.)
     ///
-    /// [here]: crate::ptr#safety
-    /// [`as_ref`]: #method.as_ref
+    /// [the module documentation]: crate::ptr#safety
     ///
     /// # Examples
     ///
@@ -272,6 +332,7 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T
     /// let ptr: *mut u32 = s.as_mut_ptr();
     /// let first_value = unsafe { ptr.as_mut().unwrap() };
     /// *first_value = 4;
+    /// # assert_eq!(s, [4, 2, 3]);
     /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
     /// ```
     ///
@@ -286,6 +347,7 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T
     /// let ptr: *mut u32 = s.as_mut_ptr();
     /// let first_value = unsafe { &mut *ptr };
     /// *first_value = 4;
+    /// # assert_eq!(s, [4, 2, 3]);
     /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
@@ -296,6 +358,43 @@ pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
         if self.is_null() { None } else { unsafe { Some(&mut *self) } }
     }
 
+    /// Returns `None` if the pointer is null, or else returns a unique reference to
+    /// the value wrapped in `Some`. In contrast to [`as_mut`], this does not require
+    /// that the value has to be initialized.
+    ///
+    /// For the shared counterpart see [`as_uninit_ref`].
+    ///
+    /// [`as_mut`]: #method.as_mut
+    /// [`as_uninit_ref`]: #method.as_uninit_ref-1
+    ///
+    /// # Safety
+    ///
+    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// all of the following is true:
+    ///
+    /// * The pointer must be properly aligned.
+    ///
+    /// * It must be "dereferencable" in the sense defined in [the module documentation].
+    ///
+    /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+    ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   not get accessed (read or written) through any other pointer.
+    ///
+    /// This applies even if the result of this method is unused!
+    ///
+    /// [the module documentation]: crate::ptr#safety
+    #[inline]
+    #[unstable(feature = "ptr_as_uninit", issue = "75402")]
+    pub unsafe fn as_uninit_mut<'a>(self) -> Option<&'a mut MaybeUninit<T>>
+    where
+        T: Sized,
+    {
+        // SAFETY: the caller must guarantee that `self` meets all the
+        // requirements for a reference.
+        if self.is_null() { None } else { Some(unsafe { &mut *(self as *mut MaybeUninit<T>) }) }
+    }
+
     /// Returns whether two pointers are guaranteed to be equal.
     ///
     /// At runtime this function behaves like `self == other`.
@@ -375,6 +474,9 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     ///   byte past the end of the same allocated object. Note that in Rust,
     ///   every (stack-allocated) variable is considered a separate allocated object.
     ///
+    /// * Both pointers must be *derived from* a pointer to the same object.
+    ///   (See below for an example.)
+    ///
     /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
     ///
     /// * The distance between the pointers, in bytes, must be an exact multiple
@@ -420,65 +522,34 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     ///     assert_eq!(ptr2.offset(-2), ptr1);
     /// }
     /// ```
-    #[unstable(feature = "ptr_offset_from", issue = "41079")]
-    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
-    #[inline]
-    pub const unsafe fn offset_from(self, origin: *const T) -> isize
-    where
-        T: Sized,
-    {
-        // SAFETY: the caller must uphold the safety contract for `offset_from`.
-        unsafe { (self as *const T).offset_from(origin) }
-    }
-
-    /// Calculates the distance between two pointers. The returned value is in
-    /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
-    ///
-    /// If the address different between the two pointers is not a multiple of
-    /// `mem::size_of::<T>()` then the result of the division is rounded towards
-    /// zero.
-    ///
-    /// Though this method is safe for any two pointers, note that its result
-    /// will be mostly useless if the two pointers aren't into the same allocated
-    /// object, for example if they point to two different local variables.
-    ///
-    /// # Panics
     ///
-    /// This function panics if `T` is a zero-sized type.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
+    /// *Incorrect* usage:
     ///
-    /// ```
-    /// #![feature(ptr_wrapping_offset_from)]
+    /// ```rust,no_run
+    /// #![feature(ptr_offset_from)]
     ///
-    /// let mut a = [0; 5];
-    /// let ptr1: *mut i32 = &mut a[1];
-    /// let ptr2: *mut i32 = &mut a[3];
-    /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
-    /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2);
-    /// assert_eq!(ptr1.wrapping_offset(2), ptr2);
-    /// assert_eq!(ptr2.wrapping_offset(-2), ptr1);
-    ///
-    /// let ptr1: *mut i32 = 3 as _;
-    /// let ptr2: *mut i32 = 13 as _;
-    /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
+    /// let ptr1 = Box::into_raw(Box::new(0u8));
+    /// let ptr2 = Box::into_raw(Box::new(1u8));
+    /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize);
+    /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1.
+    /// let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff);
+    /// assert_eq!(ptr2 as usize, ptr2_other as usize);
+    /// // Since ptr2_other and ptr2 are derived from pointers to different objects,
+    /// // computing their offset is undefined behavior, even though
+    /// // they point to the same address!
+    /// unsafe {
+    ///     let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior
+    /// }
     /// ```
-    #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
-    #[rustc_deprecated(
-        since = "1.46.0",
-        reason = "Pointer distances across allocation \
-        boundaries are not typically meaningful. \
-        Use integer subtraction if you really need this."
-    )]
+    #[stable(feature = "ptr_offset_from", since = "1.46.0")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
     #[inline]
-    pub fn wrapping_offset_from(self, origin: *const T) -> isize
+    pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
         T: Sized,
     {
-        #[allow(deprecated_in_future, deprecated)]
-        (self as *const T).wrapping_offset_from(origin)
+        // SAFETY: the caller must uphold the safety contract for `offset_from`.
+        unsafe { (self as *const T).offset_from(origin) }
     }
 
     /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
@@ -1131,6 +1202,110 @@ pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
         // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
         unsafe { index.get_unchecked_mut(self) }
     }
+
+    /// Returns `None` if the pointer is null, or else returns a shared slice to
+    /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
+    /// that the value has to be initialized.
+    ///
+    /// For the mutable counterpart see [`as_uninit_slice_mut`].
+    ///
+    /// [`as_ref`]: #method.as_ref-1
+    /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut
+    ///
+    /// # Safety
+    ///
+    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// all of the following is true:
+    ///
+    /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
+    ///   and it must be properly aligned. This means in particular:
+    ///
+    ///     * The entire memory range of this slice must be contained within a single allocated object!
+    ///       Slices can never span across multiple allocated objects.
+    ///
+    ///     * The pointer must be aligned even for zero-length slices. One
+    ///       reason for this is that enum layout optimizations may rely on references
+    ///       (including slices of any length) being aligned and non-null to distinguish
+    ///       them from other data. You can obtain a pointer that is usable as `data`
+    ///       for zero-length slices using [`NonNull::dangling()`].
+    ///
+    /// * The total size `ptr.len() * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+    ///   See the safety documentation of [`pointer::offset`].
+    ///
+    /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+    ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   not get mutated (except inside `UnsafeCell`).
+    ///
+    /// This applies even if the result of this method is unused!
+    ///
+    /// See also [`slice::from_raw_parts`][].
+    ///
+    /// [valid]: crate::ptr#safety
+    /// [`NonNull::dangling()`]: NonNull::dangling
+    /// [`pointer::offset`]: ../std/primitive.pointer.html#method.offset
+    #[inline]
+    #[unstable(feature = "ptr_as_uninit", issue = "75402")]
+    pub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]> {
+        if self.is_null() {
+            None
+        } else {
+            // SAFETY: the caller must uphold the safety contract for `as_uninit_slice`.
+            Some(unsafe { slice::from_raw_parts(self as *const MaybeUninit<T>, self.len()) })
+        }
+    }
+
+    /// Returns `None` if the pointer is null, or else returns a unique slice to
+    /// the value wrapped in `Some`. In contrast to [`as_mut`], this does not require
+    /// that the value has to be initialized.
+    ///
+    /// For the shared counterpart see [`as_uninit_slice`].
+    ///
+    /// [`as_mut`]: #method.as_mut
+    /// [`as_uninit_slice`]: #method.as_uninit_slice-1
+    ///
+    /// # Safety
+    ///
+    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// all of the following is true:
+    ///
+    /// * The pointer must be [valid] for reads and writes for `ptr.len() * mem::size_of::<T>()`
+    ///   many bytes, and it must be properly aligned. This means in particular:
+    ///
+    ///     * The entire memory range of this slice must be contained within a single allocated object!
+    ///       Slices can never span across multiple allocated objects.
+    ///
+    ///     * The pointer must be aligned even for zero-length slices. One
+    ///       reason for this is that enum layout optimizations may rely on references
+    ///       (including slices of any length) being aligned and non-null to distinguish
+    ///       them from other data. You can obtain a pointer that is usable as `data`
+    ///       for zero-length slices using [`NonNull::dangling()`].
+    ///
+    /// * The total size `ptr.len() * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+    ///   See the safety documentation of [`pointer::offset`].
+    ///
+    /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+    ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   not get accessed (read or written) through any other pointer.
+    ///
+    /// This applies even if the result of this method is unused!
+    ///
+    /// See also [`slice::from_raw_parts_mut`][].
+    ///
+    /// [valid]: crate::ptr#safety
+    /// [`NonNull::dangling()`]: NonNull::dangling
+    /// [`pointer::offset`]: ../std/primitive.pointer.html#method.offset
+    #[inline]
+    #[unstable(feature = "ptr_as_uninit", issue = "75402")]
+    pub unsafe fn as_uninit_slice_mut<'a>(self) -> Option<&'a mut [MaybeUninit<T>]> {
+        if self.is_null() {
+            None
+        } else {
+            // SAFETY: the caller must uphold the safety contract for `as_uninit_slice_mut`.
+            Some(unsafe { slice::from_raw_parts_mut(self as *mut MaybeUninit<T>, self.len()) })
+        }
+    }
 }
 
 // Equality for pointers