@@ -474,6 +474,279 @@ impl<T: ?Sized> NonNull<T> {
474474 unsafe { NonNull :: new_unchecked ( self . as_ptr ( ) as * mut U ) }
475475 }
476476
477+ /// Calculates the offset from a pointer.
478+ ///
479+ /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
480+ /// offset of `3 * size_of::<T>()` bytes.
481+ ///
482+ /// # Safety
483+ ///
484+ /// If any of the following conditions are violated, the result is Undefined
485+ /// Behavior:
486+ ///
487+ /// * Both the starting and resulting pointer must be either in bounds or one
488+ /// byte past the end of the same [allocated object].
489+ ///
490+ /// * The computed offset, **in bytes**, cannot overflow an `isize`.
491+ ///
492+ /// * The offset being in bounds cannot rely on "wrapping around" the address
493+ /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
494+ ///
495+ /// The compiler and standard library generally tries to ensure allocations
496+ /// never reach a size where an offset is a concern. For instance, `Vec`
497+ /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
498+ /// `vec.as_ptr().add(vec.len())` is always safe.
499+ ///
500+ /// Most platforms fundamentally can't even construct such an allocation.
501+ /// For instance, no known 64-bit platform can ever serve a request
502+ /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
503+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
504+ /// more than `isize::MAX` bytes with things like Physical Address
505+ /// Extension. As such, memory acquired directly from allocators or memory
506+ /// mapped files *may* be too large to handle with this function.
507+ ///
508+ /// [allocated object]: crate::ptr#allocated-object
509+ ///
510+ /// # Examples
511+ ///
512+ /// ```
513+ /// #![feature(non_null_convenience)]
514+ /// use std::ptr::NonNull;
515+ ///
516+ /// let mut s = [1, 2, 3];
517+ /// let ptr: NonNull<u32> = NonNull::new(s.as_mut_ptr()).unwrap();
518+ ///
519+ /// unsafe {
520+ /// println!("{}", ptr.offset(1).read());
521+ /// println!("{}", ptr.offset(2).read());
522+ /// }
523+ /// ```
524+ #[ unstable( feature = "non_null_convenience" , issue = "117691" ) ]
525+ #[ rustc_const_unstable( feature = "non_null_convenience" , issue = "117691" ) ]
526+ #[ must_use = "returns a new pointer rather than modifying its argument" ]
527+ #[ inline( always) ]
528+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
529+ pub const unsafe fn offset ( self , count : isize ) -> NonNull < T >
530+ where
531+ T : Sized ,
532+ {
533+ // SAFETY: the caller must uphold the safety contract for `offset`.
534+ // Additionally safety contract of `offset` guarantees that the resulting pointer is
535+ // pointing to an allocation, there can't be an allocation at null, thus it's safe to
536+ // construct `NonNull`.
537+ unsafe { NonNull { pointer : intrinsics:: offset ( self . pointer , count) } }
538+ }
539+
540+ /// Calculates the offset from a pointer in bytes.
541+ ///
542+ /// `count` is in units of **bytes**.
543+ ///
544+ /// This is purely a convenience for casting to a `u8` pointer and
545+ /// using [offset][pointer::offset] on it. See that method for documentation
546+ /// and safety requirements.
547+ ///
548+ /// For non-`Sized` pointees this operation changes only the data pointer,
549+ /// leaving the metadata untouched.
550+ #[ unstable( feature = "non_null_convenience" , issue = "117691" ) ]
551+ #[ rustc_const_unstable( feature = "non_null_convenience" , issue = "117691" ) ]
552+ #[ must_use]
553+ #[ inline( always) ]
554+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
555+ pub const unsafe fn byte_offset ( self , count : isize ) -> Self {
556+ // SAFETY: the caller must uphold the safety contract for `offset` and `byte_offset` has
557+ // the same safety contract.
558+ // Additionally safety contract of `offset` guarantees that the resulting pointer is
559+ // pointing to an allocation, there can't be an allocation at null, thus it's safe to
560+ // construct `NonNull`.
561+ unsafe { NonNull { pointer : self . pointer . byte_offset ( count) } }
562+ }
563+
564+ /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
565+ ///
566+ /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
567+ /// offset of `3 * size_of::<T>()` bytes.
568+ ///
569+ /// # Safety
570+ ///
571+ /// If any of the following conditions are violated, the result is Undefined
572+ /// Behavior:
573+ ///
574+ /// * Both the starting and resulting pointer must be either in bounds or one
575+ /// byte past the end of the same [allocated object].
576+ ///
577+ /// * The computed offset, **in bytes**, cannot overflow an `isize`.
578+ ///
579+ /// * The offset being in bounds cannot rely on "wrapping around" the address
580+ /// space. That is, the infinite-precision sum must fit in a `usize`.
581+ ///
582+ /// The compiler and standard library generally tries to ensure allocations
583+ /// never reach a size where an offset is a concern. For instance, `Vec`
584+ /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
585+ /// `vec.as_ptr().add(vec.len())` is always safe.
586+ ///
587+ /// Most platforms fundamentally can't even construct such an allocation.
588+ /// For instance, no known 64-bit platform can ever serve a request
589+ /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
590+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
591+ /// more than `isize::MAX` bytes with things like Physical Address
592+ /// Extension. As such, memory acquired directly from allocators or memory
593+ /// mapped files *may* be too large to handle with this function.
594+ ///
595+ /// [allocated object]: crate::ptr#allocated-object
596+ ///
597+ /// # Examples
598+ ///
599+ /// ```
600+ /// #![feature(non_null_convenience)]
601+ /// use std::ptr::NonNull;
602+ ///
603+ /// let s: &str = "123";
604+ /// let ptr: NonNull<u8> = NonNull::new(s.as_ptr().cast_mut()).unwrap();
605+ ///
606+ /// unsafe {
607+ /// println!("{}", ptr.add(1).read() as char);
608+ /// println!("{}", ptr.add(2).read() as char);
609+ /// }
610+ /// ```
611+ #[ unstable( feature = "non_null_convenience" , issue = "117691" ) ]
612+ #[ rustc_const_unstable( feature = "non_null_convenience" , issue = "117691" ) ]
613+ #[ must_use = "returns a new pointer rather than modifying its argument" ]
614+ #[ inline( always) ]
615+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
616+ pub const unsafe fn add ( self , count : usize ) -> Self
617+ where
618+ T : Sized ,
619+ {
620+ // SAFETY: the caller must uphold the safety contract for `offset`.
621+ // Additionally safety contract of `offset` guarantees that the resulting pointer is
622+ // pointing to an allocation, there can't be an allocation at null, thus it's safe to
623+ // construct `NonNull`.
624+ unsafe { NonNull { pointer : intrinsics:: offset ( self . pointer , count) } }
625+ }
626+
627+ /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
628+ ///
629+ /// `count` is in units of bytes.
630+ ///
631+ /// This is purely a convenience for casting to a `u8` pointer and
632+ /// using [`add`][NonNull::add] on it. See that method for documentation
633+ /// and safety requirements.
634+ ///
635+ /// For non-`Sized` pointees this operation changes only the data pointer,
636+ /// leaving the metadata untouched.
637+ #[ unstable( feature = "non_null_convenience" , issue = "117691" ) ]
638+ #[ rustc_const_unstable( feature = "non_null_convenience" , issue = "117691" ) ]
639+ #[ must_use]
640+ #[ inline( always) ]
641+ #[ rustc_allow_const_fn_unstable( set_ptr_value) ]
642+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
643+ pub const unsafe fn byte_add ( self , count : usize ) -> Self {
644+ // SAFETY: the caller must uphold the safety contract for `add` and `byte_add` has the same
645+ // safety contract.
646+ // Additionally safety contract of `add` guarantees that the resulting pointer is pointing
647+ // to an allocation, there can't be an allocation at null, thus it's safe to construct
648+ // `NonNull`.
649+ unsafe { NonNull { pointer : self . pointer . byte_add ( count) } }
650+ }
651+
652+ /// Calculates the offset from a pointer (convenience for
653+ /// `.offset((count as isize).wrapping_neg())`).
654+ ///
655+ /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
656+ /// offset of `3 * size_of::<T>()` bytes.
657+ ///
658+ /// # Safety
659+ ///
660+ /// If any of the following conditions are violated, the result is Undefined
661+ /// Behavior:
662+ ///
663+ /// * Both the starting and resulting pointer must be either in bounds or one
664+ /// byte past the end of the same [allocated object].
665+ ///
666+ /// * The computed offset cannot exceed `isize::MAX` **bytes**.
667+ ///
668+ /// * The offset being in bounds cannot rely on "wrapping around" the address
669+ /// space. That is, the infinite-precision sum must fit in a usize.
670+ ///
671+ /// The compiler and standard library generally tries to ensure allocations
672+ /// never reach a size where an offset is a concern. For instance, `Vec`
673+ /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
674+ /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
675+ ///
676+ /// Most platforms fundamentally can't even construct such an allocation.
677+ /// For instance, no known 64-bit platform can ever serve a request
678+ /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
679+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
680+ /// more than `isize::MAX` bytes with things like Physical Address
681+ /// Extension. As such, memory acquired directly from allocators or memory
682+ /// mapped files *may* be too large to handle with this function.
683+ ///
684+ /// [allocated object]: crate::ptr#allocated-object
685+ ///
686+ /// # Examples
687+ ///
688+ /// ```
689+ /// #![feature(non_null_convenience)]
690+ /// use std::ptr::NonNull;
691+ ///
692+ /// let s: &str = "123";
693+ ///
694+ /// unsafe {
695+ /// let end: NonNull<u8> = NonNull::new(s.as_ptr().cast_mut()).unwrap().add(3);
696+ /// println!("{}", end.sub(1).read() as char);
697+ /// println!("{}", end.sub(2).read() as char);
698+ /// }
699+ /// ```
700+ #[ unstable( feature = "non_null_convenience" , issue = "117691" ) ]
701+ #[ rustc_const_unstable( feature = "non_null_convenience" , issue = "117691" ) ]
702+ #[ must_use = "returns a new pointer rather than modifying its argument" ]
703+ // We could always go back to wrapping if unchecked becomes unacceptable
704+ #[ rustc_allow_const_fn_unstable( const_int_unchecked_arith) ]
705+ #[ inline( always) ]
706+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
707+ pub const unsafe fn sub ( self , count : usize ) -> Self
708+ where
709+ T : Sized ,
710+ {
711+ if T :: IS_ZST {
712+ // Pointer arithmetic does nothing when the pointee is a ZST.
713+ self
714+ } else {
715+ // SAFETY: the caller must uphold the safety contract for `offset`.
716+ // Because the pointee is *not* a ZST, that means that `count` is
717+ // at most `isize::MAX`, and thus the negation cannot overflow.
718+ unsafe { self . offset ( intrinsics:: unchecked_sub ( 0 , count as isize ) ) }
719+ }
720+ }
721+
722+ /// Calculates the offset from a pointer in bytes (convenience for
723+ /// `.byte_offset((count as isize).wrapping_neg())`).
724+ ///
725+ /// `count` is in units of bytes.
726+ ///
727+ /// This is purely a convenience for casting to a `u8` pointer and
728+ /// using [`sub`][NonNull::sub] on it. See that method for documentation
729+ /// and safety requirements.
730+ ///
731+ /// For non-`Sized` pointees this operation changes only the data pointer,
732+ /// leaving the metadata untouched.
733+ #[ unstable( feature = "non_null_convenience" , issue = "117691" ) ]
734+ #[ rustc_const_unstable( feature = "non_null_convenience" , issue = "117691" ) ]
735+ #[ must_use]
736+ #[ inline( always) ]
737+ #[ rustc_allow_const_fn_unstable( set_ptr_value) ]
738+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
739+ pub const unsafe fn byte_sub ( self , count : usize ) -> Self {
740+ // SAFETY: the caller must uphold the safety contract for `sub` and `byte_sub` has the same
741+ // safety contract.
742+ // Additionally safety contract of `sub` guarantees that the resulting pointer is pointing
743+ // to an allocation, there can't be an allocation at null, thus it's safe to construct
744+ // `NonNull`.
745+ unsafe { NonNull { pointer : self . pointer . byte_sub ( count) } }
746+ }
747+
748+ // N.B. `wrapping_offset``, `wrapping_add`, etc are not implemented because they can wrap to null
749+
477750 /// Reads the value from `self` without moving it. This leaves the
478751 /// memory in `self` unchanged.
479752 ///
0 commit comments