Skip to content

Commit

Permalink
Make NonZero constructors generic.
Browse files Browse the repository at this point in the history
  • Loading branch information
reitermarkus committed Jan 31, 2024
1 parent 0f55e1b commit cf74423
Showing 1 changed file with 81 additions and 74 deletions.
155 changes: 81 additions & 74 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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) => {
Expand All @@ -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;
}
};
}

Expand Down Expand Up @@ -83,6 +88,79 @@ impl_zeroable_primitive!(isize);
#[rustc_diagnostic_item = "NonZero"]
pub struct NonZero<T: ZeroablePrimitive>(T);

impl<T> NonZero<T>
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<Self> {
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 ) => {
$(
Expand All @@ -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,)?
Expand Down Expand Up @@ -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<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]
Expand Down Expand Up @@ -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,
Expand All @@ -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)*
Expand Down

0 comments on commit cf74423

Please sign in to comment.