@@ -474,6 +474,279 @@ impl<T: ?Sized> NonNull<T> {
474
474
unsafe { NonNull :: new_unchecked ( self . as_ptr ( ) as * mut U ) }
475
475
}
476
476
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
+
477
750
/// Reads the value from `self` without moving it. This leaves the
478
751
/// memory in `self` unchanged.
479
752
///
0 commit comments