@@ -605,7 +605,9 @@ impl<T: ?Sized> *const T {
605
605
/// Calculates the distance between two pointers. The returned value is in
606
606
/// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
607
607
///
608
- /// This function is the inverse of [`offset`].
608
+ /// This function is the inverse of [`offset`]: it is valid to call if and only if
609
+ /// `self` could have been computed as `origin.offset(n)` for some `n`, and it will
610
+ /// then return that `n`.
609
611
///
610
612
/// [`offset`]: #method.offset
611
613
///
@@ -644,6 +646,12 @@ impl<T: ?Sized> *const T {
644
646
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
645
647
/// such large allocations either.)
646
648
///
649
+ /// The requirement for pointers to be derived from the same allocated object is primarily
650
+ /// needed for `const`-compatibility: at compile-time, pointers into *different* allocated
651
+ /// object do not have a known distance to each other. However, the requirement also exists at
652
+ /// runtime, and may be exploited by optimizations. You can use `(self as usize).sub(origin as
653
+ /// usize) / mem::size_of::<T>()` to avoid this requirement.
654
+ ///
647
655
/// [`add`]: #method.add
648
656
/// [allocated object]: crate::ptr#allocated-object
649
657
///
@@ -701,7 +709,7 @@ impl<T: ?Sized> *const T {
701
709
/// units of **bytes**.
702
710
///
703
711
/// This is purely a convenience for casting to a `u8` pointer and
704
- /// using [offset_from][pointer::offset_from] on it. See that method for
712
+ /// using [` offset_from` ][pointer::offset_from] on it. See that method for
705
713
/// documentation and safety requirements.
706
714
///
707
715
/// For non-`Sized` pointees this operation considers only the data pointers,
@@ -799,6 +807,108 @@ impl<T: ?Sized> *const T {
799
807
unsafe { intrinsics:: ptr_offset_from_unsigned ( self , origin) }
800
808
}
801
809
810
+ /// Calculates the distance between two pointers using wrapping arithmetic. The returned value
811
+ /// is in units of T: the distance in bytes divided by `mem::size_of::<T>()`.
812
+ ///
813
+ /// This function is the inverse of [`wrapping_offset`]: it is valid to call if and only if
814
+ /// `self` could have been computed as `origin.wrapping_offset(n)` for some `n`, and it will
815
+ /// then return that `n`.
816
+ ///
817
+ /// [`wrapping_offset`]: #method.wrapping_offset
818
+ ///
819
+ /// # Safety
820
+ ///
821
+ /// If any of the following conditions are violated, the result is Undefined
822
+ /// Behavior:
823
+ ///
824
+ /// * Both pointers must be *derived from* a pointer to the same [allocated object].
825
+ /// (See below for an example.)
826
+ ///
827
+ /// * The distance between the pointers, in bytes, must be an exact multiple
828
+ /// of the size of `T`.
829
+ ///
830
+ /// Unlike [`offset_from`][pointer::offset_from], this method does *not* require the pointers to
831
+ /// be in-bounds of the object they are derived from, nor does it impose any restrictions
832
+ /// regarding the maximum distance or wrapping around the address space.
833
+ ///
834
+ /// The requirement for pointers to be derived from the same allocated object is primarily
835
+ /// needed for `const`-compatibility: at compile-time, pointers into *different* allocated
836
+ /// object do not have a known distance to each other. However, the requirement also exists at
837
+ /// runtime, and may be exploited by optimizations. You can use `(self as usize).sub(origin as
838
+ /// usize) / mem::size_of::<T>()` to avoid this requirement.
839
+ ///
840
+ /// [allocated object]: crate::ptr#allocated-object
841
+ ///
842
+ /// # Panics
843
+ ///
844
+ /// This function panics if `T` is a Zero-Sized Type ("ZST").
845
+ ///
846
+ /// # Examples
847
+ ///
848
+ /// Basic usage:
849
+ ///
850
+ /// ```
851
+ /// #![feature(ptr_wrapping_offset_from)]
852
+ /// let a = [0; 2];
853
+ /// let ptr1: *const i32 = &a[1];
854
+ /// let ptr2: *const i32 = a.as_ptr().wrapping_offset(3); // out-of-bounds!
855
+ /// unsafe {
856
+ /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
857
+ /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2);
858
+ /// assert_eq!(ptr1.wrapping_offset(2), ptr2);
859
+ /// assert_eq!(ptr2.wrapping_offset(-2), ptr1);
860
+ /// }
861
+ /// ```
862
+ ///
863
+ /// *Incorrect* usage:
864
+ ///
865
+ /// ```rust,no_run
866
+ /// #![feature(ptr_wrapping_offset_from)]
867
+ /// let ptr1 = Box::into_raw(Box::new(0u8)) as *const u8;
868
+ /// let ptr2 = Box::into_raw(Box::new(1u8)) as *const u8;
869
+ /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize);
870
+ /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1.
871
+ /// let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff);
872
+ /// assert_eq!(ptr2 as usize, ptr2_other as usize);
873
+ /// // Since ptr2_other and ptr2 are derived from pointers to different objects,
874
+ /// // computing their offset is undefined behavior, even though
875
+ /// // they point to the same address!
876
+ /// unsafe {
877
+ /// let zero = ptr2_other.wrapping_offset_from(ptr2); // Undefined Behavior
878
+ /// }
879
+ /// ```
880
+ #[ unstable( feature = "ptr_wrapping_offset_from" , issue = "none" ) ]
881
+ #[ rustc_const_unstable( feature = "ptr_wrapping_offset_from" , issue = "none" ) ]
882
+ #[ inline]
883
+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
884
+ #[ cfg( not( bootstrap) ) ]
885
+ pub const unsafe fn wrapping_offset_from ( self , origin : * const T ) -> isize
886
+ where
887
+ T : Sized ,
888
+ {
889
+ // SAFETY: the caller must uphold the safety contract for `ptr_offset_from`.
890
+ unsafe { intrinsics:: ptr_wrapping_offset_from ( self , origin) }
891
+ }
892
+
893
+ /// Calculates the distance between two pointers using wrapping arithmetic. The returned value
894
+ /// is in units of **bytes**.
895
+ ///
896
+ /// This is purely a convenience for casting to a `u8` pointer and using
897
+ /// [`wrapping_offset_from`][pointer::wrapping_offset_from] on it. See that method for
898
+ /// documentation and safety requirements.
899
+ ///
900
+ /// For non-`Sized` pointees this operation considers only the data pointers,
901
+ /// ignoring the metadata.
902
+ #[ inline( always) ]
903
+ #[ unstable( feature = "ptr_wrapping_offset_from" , issue = "none" ) ]
904
+ #[ rustc_const_unstable( feature = "ptr_wrapping_offset_from" , issue = "none" ) ]
905
+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
906
+ #[ cfg( not( bootstrap) ) ]
907
+ pub const unsafe fn wrapping_byte_offset_from < U : ?Sized > ( self , origin : * const U ) -> isize {
908
+ // SAFETY: the caller must uphold the safety contract for `wrapping_offset_from`.
909
+ unsafe { self . cast :: < u8 > ( ) . wrapping_offset_from ( origin. cast :: < u8 > ( ) ) }
910
+ }
911
+
802
912
/// Returns whether two pointers are guaranteed to be equal.
803
913
///
804
914
/// At runtime this function behaves like `Some(self == other)`.
0 commit comments