@@ -745,8 +745,217 @@ impl<T: ?Sized> NonNull<T> {
745745 unsafe { NonNull { pointer : self . pointer . byte_sub ( count) } }
746746 }
747747
748+ /// Calculates the distance between two pointers. The returned value is in
749+ /// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
750+ ///
751+ /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::<T>() as isize)`,
752+ /// except that it has a lot more opportunities for UB, in exchange for the compiler
753+ /// better understanding what you are doing.
754+ ///
755+ /// The primary motivation of this method is for computing the `len` of an array/slice
756+ /// of `T` that you are currently representing as a "start" and "end" pointer
757+ /// (and "end" is "one past the end" of the array).
758+ /// In that case, `end.offset_from(start)` gets you the length of the array.
759+ ///
760+ /// All of the following safety requirements are trivially satisfied for this usecase.
761+ ///
762+ /// [`offset`]: #method.offset
763+ ///
764+ /// # Safety
765+ ///
766+ /// If any of the following conditions are violated, the result is Undefined
767+ /// Behavior:
768+ ///
769+ /// * Both `self` and `origin` must be either in bounds or one
770+ /// byte past the end of the same [allocated object].
771+ ///
772+ /// * Both pointers must be *derived from* a pointer to the same object.
773+ /// (See below for an example.)
774+ ///
775+ /// * The distance between the pointers, in bytes, must be an exact multiple
776+ /// of the size of `T`.
777+ ///
778+ /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
779+ ///
780+ /// * The distance being in bounds cannot rely on "wrapping around" the address space.
781+ ///
782+ /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
783+ /// address space, so two pointers within some value of any Rust type `T` will always satisfy
784+ /// the last two conditions. The standard library also generally ensures that allocations
785+ /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
786+ /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
787+ /// always satisfies the last two conditions.
788+ ///
789+ /// Most platforms fundamentally can't even construct such a large allocation.
790+ /// For instance, no known 64-bit platform can ever serve a request
791+ /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
792+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
793+ /// more than `isize::MAX` bytes with things like Physical Address
794+ /// Extension. As such, memory acquired directly from allocators or memory
795+ /// mapped files *may* be too large to handle with this function.
796+ /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
797+ /// such large allocations either.)
798+ ///
799+ /// The requirement for pointers to be derived from the same allocated object is primarily
800+ /// needed for `const`-compatibility: the distance between pointers into *different* allocated
801+ /// objects is not known at compile-time. However, the requirement also exists at
802+ /// runtime and may be exploited by optimizations. If you wish to compute the difference between
803+ /// pointers that are not guaranteed to be from the same allocation, use `(self as isize -
804+ /// origin as isize) / mem::size_of::<T>()`.
805+ // FIXME: recommend `addr()` instead of `as usize` once that is stable.
806+ ///
807+ /// [`add`]: #method.add
808+ /// [allocated object]: crate::ptr#allocated-object
809+ ///
810+ /// # Panics
811+ ///
812+ /// This function panics if `T` is a Zero-Sized Type ("ZST").
813+ ///
814+ /// # Examples
815+ ///
816+ /// Basic usage:
817+ ///
818+ /// ```
819+ /// #![feature(non_null_convenience)]
820+ /// use std::ptr::NonNull;
821+ ///
822+ /// let a = [0; 5];
823+ /// let ptr1: NonNull<u32> = NonNull::from(&a[1]);
824+ /// let ptr2: NonNull<u32> = NonNull::from(&a[3]);
825+ /// unsafe {
826+ /// assert_eq!(ptr2.offset_from(ptr1), 2);
827+ /// assert_eq!(ptr1.offset_from(ptr2), -2);
828+ /// assert_eq!(ptr1.offset(2), ptr2);
829+ /// assert_eq!(ptr2.offset(-2), ptr1);
830+ /// }
831+ /// ```
832+ ///
833+ /// *Incorrect* usage:
834+ ///
835+ /// ```rust,no_run
836+ /// #![feature(non_null_convenience, strict_provenance)]
837+ /// use std::ptr::NonNull;
838+ ///
839+ /// let ptr1 = NonNull::new(Box::into_raw(Box::new(0u8))).unwrap();
840+ /// let ptr2 = NonNull::new(Box::into_raw(Box::new(1u8))).unwrap();
841+ /// let diff = (ptr2.addr().get() as isize).wrapping_sub(ptr1.addr().get() as isize);
842+ /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1.
843+ /// let ptr2_other = NonNull::new(ptr1.as_ptr().wrapping_byte_offset(diff)).unwrap();
844+ /// assert_eq!(ptr2.addr(), ptr2_other.addr());
845+ /// // Since ptr2_other and ptr2 are derived from pointers to different objects,
846+ /// // computing their offset is undefined behavior, even though
847+ /// // they point to the same address!
848+ /// unsafe {
849+ /// let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior
850+ /// }
851+ /// ```
852+ #[ unstable( feature = "non_null_convenience" , issue = "117691" ) ]
853+ #[ rustc_const_unstable( feature = "non_null_convenience" , issue = "117691" ) ]
854+ #[ inline]
855+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
856+ pub const unsafe fn offset_from ( self , origin : NonNull < T > ) -> isize
857+ where
858+ T : Sized ,
859+ {
860+ // SAFETY: the caller must uphold the safety contract for `offset_from`.
861+ unsafe { self . pointer . offset_from ( origin. pointer ) }
862+ }
863+
864+ /// Calculates the distance between two pointers. The returned value is in
865+ /// units of **bytes**.
866+ ///
867+ /// This is purely a convenience for casting to a `u8` pointer and
868+ /// using [`offset_from`][NonNull::offset_from] on it. See that method for
869+ /// documentation and safety requirements.
870+ ///
871+ /// For non-`Sized` pointees this operation considers only the data pointers,
872+ /// ignoring the metadata.
873+ #[ unstable( feature = "non_null_convenience" , issue = "117691" ) ]
874+ #[ rustc_const_unstable( feature = "non_null_convenience" , issue = "117691" ) ]
875+ #[ inline( always) ]
876+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
877+ pub const unsafe fn byte_offset_from < U : ?Sized > ( self , origin : NonNull < U > ) -> isize {
878+ // SAFETY: the caller must uphold the safety contract for `byte_offset_from`.
879+ unsafe { self . pointer . byte_offset_from ( origin. pointer ) }
880+ }
881+
748882 // N.B. `wrapping_offset``, `wrapping_add`, etc are not implemented because they can wrap to null
749883
884+ /// Calculates the distance between two pointers, *where it's known that
885+ /// `self` is equal to or greater than `origin`*. The returned value is in
886+ /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
887+ ///
888+ /// This computes the same value that [`offset_from`](#method.offset_from)
889+ /// would compute, but with the added precondition that the offset is
890+ /// guaranteed to be non-negative. This method is equivalent to
891+ /// `usize::try_from(self.offset_from(origin)).unwrap_unchecked()`,
892+ /// but it provides slightly more information to the optimizer, which can
893+ /// sometimes allow it to optimize slightly better with some backends.
894+ ///
895+ /// This method can be though of as recovering the `count` that was passed
896+ /// to [`add`](#method.add) (or, with the parameters in the other order,
897+ /// to [`sub`](#method.sub)). The following are all equivalent, assuming
898+ /// that their safety preconditions are met:
899+ /// ```rust
900+ /// # #![feature(non_null_convenience)]
901+ /// # unsafe fn blah(ptr: std::ptr::NonNull<u32>, origin: std::ptr::NonNull<u32>, count: usize) -> bool {
902+ /// ptr.sub_ptr(origin) == count
903+ /// # &&
904+ /// origin.add(count) == ptr
905+ /// # &&
906+ /// ptr.sub(count) == origin
907+ /// # }
908+ /// ```
909+ ///
910+ /// # Safety
911+ ///
912+ /// - The distance between the pointers must be non-negative (`self >= origin`)
913+ ///
914+ /// - *All* the safety conditions of [`offset_from`](#method.offset_from)
915+ /// apply to this method as well; see it for the full details.
916+ ///
917+ /// Importantly, despite the return type of this method being able to represent
918+ /// a larger offset, it's still *not permitted* to pass pointers which differ
919+ /// by more than `isize::MAX` *bytes*. As such, the result of this method will
920+ /// always be less than or equal to `isize::MAX as usize`.
921+ ///
922+ /// # Panics
923+ ///
924+ /// This function panics if `T` is a Zero-Sized Type ("ZST").
925+ ///
926+ /// # Examples
927+ ///
928+ /// ```
929+ /// #![feature(non_null_convenience)]
930+ /// use std::ptr::NonNull;
931+ ///
932+ /// let a = [0; 5];
933+ /// let ptr1: NonNull<u32> = NonNull::from(&a[1]);
934+ /// let ptr2: NonNull<u32> = NonNull::from(&a[3]);
935+ /// unsafe {
936+ /// assert_eq!(ptr2.sub_ptr(ptr1), 2);
937+ /// assert_eq!(ptr1.add(2), ptr2);
938+ /// assert_eq!(ptr2.sub(2), ptr1);
939+ /// assert_eq!(ptr2.sub_ptr(ptr2), 0);
940+ /// }
941+ ///
942+ /// // This would be incorrect, as the pointers are not correctly ordered:
943+ /// // ptr1.sub_ptr(ptr2)
944+ /// ```
945+ #[ unstable( feature = "non_null_convenience" , issue = "117691" ) ]
946+ #[ rustc_const_unstable( feature = "non_null_convenience" , issue = "117691" ) ]
947+ // #[unstable(feature = "ptr_sub_ptr", issue = "95892")]
948+ // #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
949+ #[ inline]
950+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
951+ pub const unsafe fn sub_ptr ( self , subtracted : NonNull < T > ) -> usize
952+ where
953+ T : Sized ,
954+ {
955+ // SAFETY: the caller must uphold the safety contract for `sub_ptr`.
956+ unsafe { self . pointer . sub_ptr ( subtracted. pointer ) }
957+ }
958+
750959 /// Reads the value from `self` without moving it. This leaves the
751960 /// memory in `self` unchanged.
752961 ///
@@ -978,17 +1187,6 @@ impl<T: ?Sized> NonNull<T> {
9781187 // SAFETY: the caller must uphold the safety contract for `write_unaligned`.
9791188 unsafe { ptr:: write_unaligned ( self . as_ptr ( ) , val) }
9801189 }
981-
982- /// See [`pointer::sub_ptr`] for semantics and safety requirements.
983- #[ inline]
984- pub ( crate ) const unsafe fn sub_ptr ( self , subtrahend : Self ) -> usize
985- where
986- T : Sized ,
987- {
988- // SAFETY: The caller promised that this is safe to do, and
989- // the non-nullness is irrelevant to the operation.
990- unsafe { self . pointer . sub_ptr ( subtrahend. pointer ) }
991- }
9921190}
9931191
9941192impl < T > NonNull < [ T ] > {
0 commit comments