diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index ea922970b92d8..5b464d089e244 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1,6 +1,6 @@ //! Definitions of integer that is known not to equal zero. -use crate::cmp::Ordering; +use crate::cmp::{Ordering, PartialEq}; use crate::fmt; use crate::hash::{Hash, Hasher}; #[cfg(bootstrap)] @@ -32,7 +32,10 @@ mod private { issue = "none" )] #[const_trait] -pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {} +pub trait ZeroablePrimitive: Sized + Copy + private::Sealed { + #[doc(hidden)] + const ZERO: Self; +} macro_rules! impl_zeroable_primitive { ($primitive:ty) => { @@ -48,7 +51,9 @@ macro_rules! impl_zeroable_primitive { reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - impl const ZeroablePrimitive for $primitive {} + impl const ZeroablePrimitive for $primitive { + const ZERO: Self = 0; + } }; } @@ -83,6 +88,79 @@ impl_zeroable_primitive!(isize); #[rustc_diagnostic_item = "NonZero"] pub struct NonZero(T); +impl NonZero +where + T: ZeroablePrimitive + PartialEq, +{ + /// 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")] + #[must_use] + #[inline] + pub const fn new(n: T) -> Option { + if n == T::ZERO { + return None; + } + + // SAFETY: We just checked that there's no `0`. + Some(unsafe { Self(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 { + crate::panic::debug_assert_nounwind!( + n != T::ZERO, + "NonZero::new_unchecked requires a non-zero argument", + ); + + // SAFETY: This is guaranteed to be safe by the caller. + unsafe { Self(n) } + } + + /// 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: 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 != T::ZERO).then(|| unsafe { &mut *(n as *mut T as *mut Self) }) + } + + /// 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 { + // 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!( + "NonZero::from_mut_unchecked requires the argument to dereference as non-zero", + [T: ZeroablePrimitive + PartialEq](n_alias: &mut T) => *n_alias != T::ZERO + ); + &mut *(n as *mut T as *mut Self) + } + } +} + macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( @@ -100,7 +178,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 +220,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 +733,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 +743,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)*