diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index ea922970b92d8..8cbbc2aa1a24c 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); +impl NonZero +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 { + // SAFETY: Memory layout optimization guarantees that `Option>` 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>` has + // the same layout and size as `T`, with `0` representing `None`. + let opt_n = unsafe { &mut *(n as *mut T as *mut Option) }; + + 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 { - 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)*