@@ -745,8 +745,217 @@ impl<T: ?Sized> NonNull<T> {
745
745
unsafe { NonNull { pointer : self . pointer . byte_sub ( count) } }
746
746
}
747
747
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
+
748
882
// N.B. `wrapping_offset``, `wrapping_add`, etc are not implemented because they can wrap to null
749
883
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
+
750
959
/// Reads the value from `self` without moving it. This leaves the
751
960
/// memory in `self` unchanged.
752
961
///
@@ -978,17 +1187,6 @@ impl<T: ?Sized> NonNull<T> {
978
1187
// SAFETY: the caller must uphold the safety contract for `write_unaligned`.
979
1188
unsafe { ptr:: write_unaligned ( self . as_ptr ( ) , val) }
980
1189
}
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
- }
992
1190
}
993
1191
994
1192
impl < T > NonNull < [ T ] > {
0 commit comments