From e9af03a22279b62ded4c7ea897d5ac3a9b54728c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 29 Jun 2017 01:00:00 +0200 Subject: [PATCH] =?UTF-8?q?Add=20`new=5Fchecked(=E2=80=A6)=20->=20Option`=20to=20NonZero,=20Unique,=20and=20Shared.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libcore/nonzero.rs | 68 ++++++++++++++++++++++++++++++++---------- src/libcore/ptr.rs | 14 +++++++-- 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 977438051d9..0564d73dd6d 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -16,22 +16,48 @@ use ops::CoerceUnsized; /// Unsafe trait to indicate what types are usable with the NonZero struct -pub unsafe trait Zeroable {} +pub unsafe trait Zeroable { + /// Whether this value is zero + fn is_zero(&self) -> bool; +} -unsafe impl Zeroable for *const T {} -unsafe impl Zeroable for *mut T {} -unsafe impl Zeroable for isize {} -unsafe impl Zeroable for usize {} -unsafe impl Zeroable for i8 {} -unsafe impl Zeroable for u8 {} -unsafe impl Zeroable for i16 {} -unsafe impl Zeroable for u16 {} -unsafe impl Zeroable for i32 {} -unsafe impl Zeroable for u32 {} -unsafe impl Zeroable for i64 {} -unsafe impl Zeroable for u64 {} -unsafe impl Zeroable for i128 {} -unsafe impl Zeroable for u128 {} +macro_rules! impl_zeroable_for_pointer_types { + ( $( $Ptr: ty )+ ) => { + $( + /// For fat pointers to be considered "zero", only the "data" part needs to be null. + unsafe impl Zeroable for $Ptr { + #[inline] + fn is_zero(&self) -> bool { + // Cast because `is_null` is only available on thin pointers + (*self as *mut u8).is_null() + } + } + )+ + } +} + +macro_rules! impl_zeroable_for_integer_types { + ( $( $Int: ty )+ ) => { + $( + unsafe impl Zeroable for $Int { + #[inline] + fn is_zero(&self) -> bool { + *self == 0 + } + } + )+ + } +} + +impl_zeroable_for_pointer_types! { + *const T + *mut T +} + +impl_zeroable_for_integer_types! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 +} /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. @@ -43,10 +69,20 @@ impl NonZero { /// Creates an instance of NonZero with the provided value. /// You must indeed ensure that the value is actually "non-zero". #[inline] - pub const unsafe fn new(inner: T) -> NonZero { + pub const unsafe fn new(inner: T) -> Self { NonZero(inner) } + /// Creates an instance of NonZero with the provided value. + #[inline] + pub fn new_checked(inner: T) -> Option { + if inner.is_zero() { + None + } else { + Some(NonZero(inner)) + } + } + /// Gets the inner value. pub fn get(self) -> T { self.0 diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b19e07b8578..e83ca63834a 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1110,10 +1110,15 @@ impl Unique { /// # Safety /// /// `ptr` must be non-null. - pub const unsafe fn new(ptr: *mut T) -> Unique { + pub const unsafe fn new(ptr: *mut T) -> Self { Unique { pointer: NonZero::new(ptr), _marker: PhantomData } } + /// Creates a new `Unique` if `ptr` is non-null. + pub fn new_checked(ptr: *mut T) -> Option { + NonZero::new_checked(ptr as *const T).map(|nz| Unique { pointer: nz, _marker: PhantomData }) + } + /// Acquires the underlying `*mut` pointer. pub fn as_ptr(self) -> *mut T { self.pointer.get() as *mut T @@ -1224,10 +1229,15 @@ impl Shared { /// # Safety /// /// `ptr` must be non-null. - pub unsafe fn new(ptr: *mut T) -> Self { + pub const unsafe fn new(ptr: *mut T) -> Self { Shared { pointer: NonZero::new(ptr), _marker: PhantomData } } + /// Creates a new `Shared` if `ptr` is non-null. + pub fn new_checked(ptr: *mut T) -> Option { + NonZero::new_checked(ptr as *const T).map(|nz| Shared { pointer: nz, _marker: PhantomData }) + } + /// Acquires the underlying `*mut` pointer. pub fn as_ptr(self) -> *mut T { self.pointer.get() as *mut T