about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarkus Reiter <me@reitermark.us>2024-01-22 18:04:05 +0100
committerMarkus Reiter <me@reitermark.us>2024-02-07 12:47:49 +0100
commita67b72c74e8b59eb0eeb48767cb37e6c1a139329 (patch)
tree01c1ac7dd222b8ea9ca4e203ecdce423e2dfe54c
parent58d70d6805565ec2208a88f2d8d414fc940beed6 (diff)
downloadrust-a67b72c74e8b59eb0eeb48767cb37e6c1a139329.tar.gz
rust-a67b72c74e8b59eb0eeb48767cb37e6c1a139329.zip
Make `NonZero` constructors generic.
-rw-r--r--library/core/src/num/nonzero.rs155
1 files changed, 84 insertions, 71 deletions
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index ea922970b92..8cbbc2aa1a2 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -83,6 +83,90 @@ impl_zeroable_primitive!(isize);
 #[rustc_diagnostic_item = "NonZero"]
 pub struct NonZero<T: ZeroablePrimitive>(T);
 
+impl<T> NonZero<T>
+where
+    T: ZeroablePrimitive,
+{
+    /// Creates a non-zero if the given value is not zero.
+    #[stable(feature = "nonzero", since = "1.28.0")]
+    #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")]
+    #[rustc_allow_const_fn_unstable(const_refs_to_cell)]
+    #[must_use]
+    #[inline]
+    pub const fn new(n: T) -> Option<Self> {
+        // SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
+        //         the same layout and size as `T`, with `0` representing `None`.
+        unsafe { crate::mem::transmute_copy(&n) }
+    }
+
+    /// Creates a non-zero without checking whether the value is non-zero.
+    /// This results in undefined behaviour if the value is zero.
+    ///
+    /// # Safety
+    ///
+    /// The value must not be zero.
+    #[stable(feature = "nonzero", since = "1.28.0")]
+    #[rustc_const_stable(feature = "nonzero", since = "1.28.0")]
+    #[must_use]
+    #[inline]
+    pub const unsafe fn new_unchecked(n: T) -> Self {
+        match Self::new(n) {
+            Some(n) => n,
+            None => {
+                // SAFETY: The caller guarantees that `n` is non-zero, so this is unreachable.
+                unsafe {
+                    crate::intrinsics::assert_unsafe_precondition!(
+                        "NonZero::new_unchecked requires the argument to be non-zero",
+                        () => false
+                    );
+
+                    crate::hint::unreachable_unchecked()
+                }
+            }
+        }
+    }
+
+    /// Converts a reference to a non-zero mutable reference
+    /// if the referenced value is not zero.
+    #[unstable(feature = "nonzero_from_mut", issue = "106290")]
+    #[must_use]
+    #[inline]
+    pub fn from_mut(n: &mut T) -> Option<&mut Self> {
+        // SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
+        //         the same layout and size as `T`, with `0` representing `None`.
+        let opt_n = unsafe { &mut *(n as *mut T as *mut Option<Self>) };
+
+        opt_n.as_mut()
+    }
+
+    /// Converts a mutable reference to a non-zero mutable reference
+    /// without checking whether the referenced value is non-zero.
+    /// This results in undefined behavior if the referenced value is zero.
+    ///
+    /// # Safety
+    ///
+    /// The referenced value must not be zero.
+    #[unstable(feature = "nonzero_from_mut", issue = "106290")]
+    #[must_use]
+    #[inline]
+    pub unsafe fn from_mut_unchecked(n: &mut T) -> &mut Self {
+        match Self::from_mut(n) {
+            Some(n) => n,
+            None => {
+                // SAFETY: The caller guarantees that `n` references a value that is non-zero, so this is unreachable.
+                unsafe {
+                    crate::intrinsics::assert_unsafe_precondition!(
+                      "NonZero::from_mut_unchecked requires the argument to dereference as non-zero",
+                        () => false
+                    );
+
+                    crate::hint::unreachable_unchecked()
+                }
+            }
+        }
+    }
+}
+
 macro_rules! impl_nonzero_fmt {
     ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
         $(
@@ -100,7 +184,6 @@ macro_rules! impl_nonzero_fmt {
 macro_rules! nonzero_integer {
     (
         #[$stability:meta]
-        #[$const_new_unchecked_stability:meta]
         Self = $Ty:ident,
         Primitive = $signedness:ident $Int:ident,
         $(UnsignedNonZero = $UnsignedNonZero:ident,)?
@@ -143,74 +226,6 @@ macro_rules! nonzero_integer {
         pub type $Ty = NonZero<$Int>;
 
         impl $Ty {
-            /// Creates a non-zero without checking whether the value is non-zero.
-            /// This results in undefined behaviour if the value is zero.
-            ///
-            /// # Safety
-            ///
-            /// The value must not be zero.
-            #[$stability]
-            #[$const_new_unchecked_stability]
-            #[must_use]
-            #[inline]
-            pub const unsafe fn new_unchecked(n: $Int) -> Self {
-                crate::panic::debug_assert_nounwind!(
-                    n != 0,
-                    concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument")
-                );
-                // SAFETY: this is guaranteed to be safe by the caller.
-                unsafe {
-                    Self(n)
-                }
-            }
-
-            /// Creates a non-zero if the given value is not zero.
-            #[$stability]
-            #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")]
-            #[must_use]
-            #[inline]
-            pub const fn new(n: $Int) -> Option<Self> {
-                if n != 0 {
-                    // SAFETY: we just checked that there's no `0`
-                    Some(unsafe { Self(n) })
-                } else {
-                    None
-                }
-            }
-
-            /// Converts a primitive mutable reference to a non-zero mutable reference
-            /// without checking whether the referenced value is non-zero.
-            /// This results in undefined behavior if `*n` is zero.
-            ///
-            /// # Safety
-            /// The referenced value must not be currently zero.
-            #[unstable(feature = "nonzero_from_mut", issue = "106290")]
-            #[must_use]
-            #[inline]
-            pub unsafe fn from_mut_unchecked(n: &mut $Int) -> &mut Self {
-                // SAFETY: Self is repr(transparent), and the value is assumed to be non-zero.
-                unsafe {
-                    let n_alias = &mut *n;
-                    core::intrinsics::assert_unsafe_precondition!(
-                        concat!(stringify!($Ty), "::from_mut_unchecked requires the argument to dereference as non-zero"),
-                        (n_alias: &mut $Int) => *n_alias != 0
-                    );
-                    &mut *(n as *mut $Int as *mut Self)
-                }
-            }
-
-            /// Converts a primitive mutable reference to a non-zero mutable reference
-            /// if the referenced integer is not zero.
-            #[unstable(feature = "nonzero_from_mut", issue = "106290")]
-            #[must_use]
-            #[inline]
-            pub fn from_mut(n: &mut $Int) -> Option<&mut Self> {
-                // SAFETY: Self is repr(transparent), and the value is non-zero.
-                // As long as the returned reference is alive,
-                // the user cannot `*n = 0` directly.
-                (*n != 0).then(|| unsafe { &mut *(n as *mut $Int as *mut Self) })
-            }
-
             /// Returns the value as a primitive type.
             #[$stability]
             #[inline]
@@ -724,7 +739,6 @@ macro_rules! nonzero_integer {
     (Self = $Ty:ident, Primitive = unsigned $Int:ident $(,)?) => {
         nonzero_integer! {
             #[stable(feature = "nonzero", since = "1.28.0")]
-            #[rustc_const_stable(feature = "nonzero", since = "1.28.0")]
             Self = $Ty,
             Primitive = unsigned $Int,
             UnsignedPrimitive = $Int,
@@ -735,7 +749,6 @@ macro_rules! nonzero_integer {
     (Self = $Ty:ident, Primitive = signed $Int:ident, $($rest:tt)*) => {
         nonzero_integer! {
             #[stable(feature = "signed_nonzero", since = "1.34.0")]
-            #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")]
             Self = $Ty,
             Primitive = signed $Int,
             $($rest)*