about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSimon Sapin <simon.sapin@exyr.org>2017-06-29 01:00:00 +0200
committerSimon Sapin <simon.sapin@exyr.org>2017-07-22 20:37:52 +0200
commite9af03a22279b62ded4c7ea897d5ac3a9b54728c (patch)
tree74c970d0be0c79dab61ba3196d808aa665a05a44
parentf8d485f53dbe87e0d7b4ad14904fd7b0447a8cbe (diff)
downloadrust-e9af03a22279b62ded4c7ea897d5ac3a9b54728c.tar.gz
rust-e9af03a22279b62ded4c7ea897d5ac3a9b54728c.zip
Add `new_checked(…) -> Option<Self>` to NonZero, Unique, and Shared.
-rw-r--r--src/libcore/nonzero.rs70
-rw-r--r--src/libcore/ptr.rs14
2 files changed, 65 insertions, 19 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 {}
-
-unsafe impl<T:?Sized> Zeroable for *const T {}
-unsafe impl<T:?Sized> 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 {}
+pub unsafe trait Zeroable {
+    /// Whether this value is zero
+    fn is_zero(&self) -> bool;
+}
+
+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<T: ?Sized> 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<T: Zeroable> NonZero<T> {
     /// 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<T> {
+    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<Self> {
+        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<T: ?Sized> Unique<T> {
     /// # Safety
     ///
     /// `ptr` must be non-null.
-    pub const unsafe fn new(ptr: *mut T) -> Unique<T> {
+    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<Self> {
+        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<T: ?Sized> Shared<T> {
     /// # 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<Self> {
+        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