Skip to content

Commit 36a587f

Browse files
committed
Add read/write/copy convenience methods to NonNull
1 parent 0b8a61b commit 36a587f

File tree

1 file changed

+223
-14
lines changed

1 file changed

+223
-14
lines changed

Diff for: library/core/src/ptr/non_null.rs

+223-14
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ use crate::cmp::Ordering;
22
use crate::convert::From;
33
use crate::fmt;
44
use crate::hash;
5+
use crate::intrinsics;
56
use crate::intrinsics::assert_unsafe_precondition;
67
use crate::marker::Unsize;
8+
use crate::mem::SizedTypeProperties;
79
use crate::mem::{self, MaybeUninit};
810
use crate::num::NonZeroUsize;
911
use crate::ops::{CoerceUnsized, DispatchFromDyn};
12+
use crate::ptr;
1013
use crate::ptr::Unique;
1114
use crate::slice::{self, SliceIndex};
1215

@@ -471,30 +474,236 @@ impl<T: ?Sized> NonNull<T> {
471474
unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) }
472475
}
473476

474-
/// See [`pointer::add`] for semantics and safety requirements.
477+
/// Reads the value from `self` without moving it. This leaves the
478+
/// memory in `self` unchanged.
479+
///
480+
/// See [`ptr::read`] for safety concerns and examples.
481+
///
482+
/// [`ptr::read`]: crate::ptr::read()
483+
#[unstable(feature = "non_null_convenience", issue = "117691")]
484+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
475485
#[inline]
476-
pub(crate) const unsafe fn add(self, delta: usize) -> Self
486+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
487+
pub const unsafe fn read(self) -> T
477488
where
478489
T: Sized,
479490
{
480-
// SAFETY: We require that the delta stays in-bounds of the object, and
481-
// thus it cannot become null, as that would require wrapping the
482-
// address space, which no legal objects are allowed to do.
483-
// And the caller promised the `delta` is sound to add.
484-
unsafe { NonNull { pointer: self.pointer.add(delta) } }
491+
// SAFETY: the caller must uphold the safety contract for `read`.
492+
unsafe { ptr::read(self.pointer) }
485493
}
486494

487-
/// See [`pointer::sub`] for semantics and safety requirements.
495+
/// Performs a volatile read of the value from `self` without moving it. This
496+
/// leaves the memory in `self` unchanged.
497+
///
498+
/// Volatile operations are intended to act on I/O memory, and are guaranteed
499+
/// to not be elided or reordered by the compiler across other volatile
500+
/// operations.
501+
///
502+
/// See [`ptr::read_volatile`] for safety concerns and examples.
503+
///
504+
/// [`ptr::read_volatile`]: crate::ptr::read_volatile()
505+
#[unstable(feature = "non_null_convenience", issue = "117691")]
488506
#[inline]
489-
pub(crate) const unsafe fn sub(self, delta: usize) -> Self
507+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
508+
pub unsafe fn read_volatile(self) -> T
509+
where
510+
T: Sized,
511+
{
512+
// SAFETY: the caller must uphold the safety contract for `read_volatile`.
513+
unsafe { ptr::read_volatile(self.pointer) }
514+
}
515+
516+
/// Reads the value from `self` without moving it. This leaves the
517+
/// memory in `self` unchanged.
518+
///
519+
/// Unlike `read`, the pointer may be unaligned.
520+
///
521+
/// See [`ptr::read_unaligned`] for safety concerns and examples.
522+
///
523+
/// [`ptr::read_unaligned`]: crate::ptr::read_unaligned()
524+
#[unstable(feature = "non_null_convenience", issue = "117691")]
525+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
526+
#[inline]
527+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
528+
pub const unsafe fn read_unaligned(self) -> T
529+
where
530+
T: Sized,
531+
{
532+
// SAFETY: the caller must uphold the safety contract for `read_unaligned`.
533+
unsafe { ptr::read_unaligned(self.pointer) }
534+
}
535+
536+
/// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
537+
/// and destination may overlap.
538+
///
539+
/// NOTE: this has the *same* argument order as [`ptr::copy`].
540+
///
541+
/// See [`ptr::copy`] for safety concerns and examples.
542+
///
543+
/// [`ptr::copy`]: crate::ptr::copy()
544+
#[unstable(feature = "non_null_convenience", issue = "117691")]
545+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
546+
#[inline(always)]
547+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
548+
pub const unsafe fn copy_to(self, dest: NonNull<T>, count: usize)
549+
where
550+
T: Sized,
551+
{
552+
// SAFETY: the caller must uphold the safety contract for `copy`.
553+
unsafe { ptr::copy(self.pointer, dest.as_ptr(), count) }
554+
}
555+
556+
/// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
557+
/// and destination may *not* overlap.
558+
///
559+
/// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`].
560+
///
561+
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
562+
///
563+
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
564+
#[unstable(feature = "non_null_convenience", issue = "117691")]
565+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
566+
#[inline(always)]
567+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
568+
pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull<T>, count: usize)
569+
where
570+
T: Sized,
571+
{
572+
// SAFETY: the caller must uphold the safety contract for `copy_nonoverlapping`.
573+
unsafe { ptr::copy_nonoverlapping(self.pointer, dest.as_ptr(), count) }
574+
}
575+
576+
/// Copies `count * size_of<T>` bytes from `src` to `self`. The source
577+
/// and destination may overlap.
578+
///
579+
/// NOTE: this has the *opposite* argument order of [`ptr::copy`].
580+
///
581+
/// See [`ptr::copy`] for safety concerns and examples.
582+
///
583+
/// [`ptr::copy`]: crate::ptr::copy()
584+
#[unstable(feature = "non_null_convenience", issue = "117691")]
585+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
586+
#[inline(always)]
587+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
588+
pub const unsafe fn copy_from(self, src: NonNull<T>, count: usize)
589+
where
590+
T: Sized,
591+
{
592+
// SAFETY: the caller must uphold the safety contract for `copy`.
593+
unsafe { ptr::copy(src.pointer, self.as_ptr(), count) }
594+
}
595+
596+
/// Copies `count * size_of<T>` bytes from `src` to `self`. The source
597+
/// and destination may *not* overlap.
598+
///
599+
/// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`].
600+
///
601+
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
602+
///
603+
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
604+
#[unstable(feature = "non_null_convenience", issue = "117691")]
605+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
606+
#[inline(always)]
607+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
608+
pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull<T>, count: usize)
609+
where
610+
T: Sized,
611+
{
612+
// SAFETY: the caller must uphold the safety contract for `copy_nonoverlapping`.
613+
unsafe { ptr::copy_nonoverlapping(src.pointer, self.as_ptr(), count) }
614+
}
615+
616+
/// Executes the destructor (if any) of the pointed-to value.
617+
///
618+
/// See [`ptr::drop_in_place`] for safety concerns and examples.
619+
///
620+
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place()
621+
#[unstable(feature = "non_null_convenience", issue = "117691")]
622+
#[inline(always)]
623+
pub unsafe fn drop_in_place(self) {
624+
// SAFETY: the caller must uphold the safety contract for `drop_in_place`.
625+
unsafe { ptr::drop_in_place(self.as_ptr()) }
626+
}
627+
628+
/// Overwrites a memory location with the given value without reading or
629+
/// dropping the old value.
630+
///
631+
/// See [`ptr::write`] for safety concerns and examples.
632+
///
633+
/// [`ptr::write`]: crate::ptr::write()
634+
#[unstable(feature = "non_null_convenience", issue = "117691")]
635+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
636+
//#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
637+
#[inline(always)]
638+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
639+
pub const unsafe fn write(self, val: T)
640+
where
641+
T: Sized,
642+
{
643+
// SAFETY: the caller must uphold the safety contract for `write`.
644+
unsafe { ptr::write(self.as_ptr(), val) }
645+
}
646+
647+
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
648+
/// bytes of memory starting at `self` to `val`.
649+
///
650+
/// See [`ptr::write_bytes`] for safety concerns and examples.
651+
///
652+
/// [`ptr::write_bytes`]: crate::ptr::write_bytes()
653+
#[doc(alias = "memset")]
654+
#[unstable(feature = "non_null_convenience", issue = "117691")]
655+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
656+
//#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
657+
#[inline(always)]
658+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
659+
pub const unsafe fn write_bytes(self, val: u8, count: usize)
660+
where
661+
T: Sized,
662+
{
663+
// SAFETY: the caller must uphold the safety contract for `write_bytes`.
664+
unsafe { ptr::write_bytes(self.as_ptr(), val, count) }
665+
}
666+
667+
/// Performs a volatile write of a memory location with the given value without
668+
/// reading or dropping the old value.
669+
///
670+
/// Volatile operations are intended to act on I/O memory, and are guaranteed
671+
/// to not be elided or reordered by the compiler across other volatile
672+
/// operations.
673+
///
674+
/// See [`ptr::write_volatile`] for safety concerns and examples.
675+
///
676+
/// [`ptr::write_volatile`]: crate::ptr::write_volatile()
677+
#[unstable(feature = "non_null_convenience", issue = "117691")]
678+
#[inline(always)]
679+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
680+
pub unsafe fn write_volatile(self, val: T)
681+
where
682+
T: Sized,
683+
{
684+
// SAFETY: the caller must uphold the safety contract for `write_volatile`.
685+
unsafe { ptr::write_volatile(self.as_ptr(), val) }
686+
}
687+
688+
/// Overwrites a memory location with the given value without reading or
689+
/// dropping the old value.
690+
///
691+
/// Unlike `write`, the pointer may be unaligned.
692+
///
693+
/// See [`ptr::write_unaligned`] for safety concerns and examples.
694+
///
695+
/// [`ptr::write_unaligned`]: crate::ptr::write_unaligned()
696+
#[unstable(feature = "non_null_convenience", issue = "117691")]
697+
#[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")]
698+
//#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
699+
#[inline(always)]
700+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
701+
pub const unsafe fn write_unaligned(self, val: T)
490702
where
491703
T: Sized,
492704
{
493-
// SAFETY: We require that the delta stays in-bounds of the object, and
494-
// thus it cannot become null, as no legal objects can be allocated
495-
// in such as way that the null address is part of them.
496-
// And the caller promised the `delta` is sound to subtract.
497-
unsafe { NonNull { pointer: self.pointer.sub(delta) } }
705+
// SAFETY: the caller must uphold the safety contract for `write_unaligned`.
706+
unsafe { ptr::write_unaligned(self.as_ptr(), val) }
498707
}
499708

500709
/// See [`pointer::sub_ptr`] for semantics and safety requirements.

0 commit comments

Comments
 (0)