Skip to content

Commit

Permalink
Additional NonZero conversions
Browse files Browse the repository at this point in the history
  • Loading branch information
clarfonthey committed Sep 1, 2024
1 parent a48861a commit 526396f
Showing 1 changed file with 137 additions and 2 deletions.
139 changes: 137 additions & 2 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! Definitions of integer that is known not to equal zero.

use super::{IntErrorKind, ParseIntError};
use super::{IntErrorKind, ParseIntError, TryFromIntError};
use crate::cmp::Ordering;
use crate::hash::{Hash, Hasher};
use crate::marker::{Freeze, StructuralPartialEq};
use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign};
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::str::FromStr;
use crate::{fmt, intrinsics, ptr, ub_checks};
use crate::{fmt, hint, intrinsics, ptr, slice, ub_checks};

/// A marker trait for primitive types which can be zero.
///
Expand Down Expand Up @@ -273,6 +273,77 @@ where
}
}

#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
impl<'a, T> From<&'a NonZero<T>> for &'a T
where
T: ZeroablePrimitive,
{
#[inline]
fn from(nonzero: &'a NonZero<T>) -> &'a T {
nonzero.as_ref()
}
}

#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
impl<'a, T> From<&'a [NonZero<T>]> for &'a [T]
where
T: ZeroablePrimitive,
{
#[inline]
fn from(nonzero: &'a [NonZero<T>]) -> &'a [T] {
nonzero.as_zeroable()
}
}

#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
impl<T, const N: usize> From<[NonZero<T>; N]> for [T; N]
where
T: ZeroablePrimitive,
{
#[inline]
fn from(nonzero: [NonZero<T>; N]) -> [T; N] {
nonzero.into_zeroable()
}
}

#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
impl<'a, T> TryFrom<&'a T> for &'a NonZero<T>
where
T: ZeroablePrimitive,
{
type Error = TryFromIntError;

#[inline]
fn try_from(zeroable: &'a T) -> Result<&'a NonZero<T>, TryFromIntError> {
NonZero::from_ref(zeroable).ok_or(TryFromIntError(()))
}
}

#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
impl<'a, T> TryFrom<&'a [T]> for &'a [NonZero<T>]
where
T: ZeroablePrimitive,
{
type Error = TryFromIntError;

#[inline]
fn try_from(zeroable: &'a [T]) -> Result<&'a [NonZero<T>], TryFromIntError> {
NonZero::from_slice(zeroable).ok_or(TryFromIntError(()))
}
}

#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
impl<T, const N: usize> TryFrom<[T; N]> for [NonZero<T>; N]
where
T: ZeroablePrimitive,
{
type Error = TryFromIntError;

#[inline]
fn try_from(zeroable: [T; N]) -> Result<[NonZero<T>; N], TryFromIntError> {
NonZero::from_array(zeroable).ok_or(TryFromIntError(()))
}
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
impl<T> BitOr for NonZero<T>
where
Expand Down Expand Up @@ -421,6 +492,45 @@ where
}
}

/// Implementation of `From<&NonZero<T>> for &T`.
#[must_use]
#[inline]
fn as_ref(&self) -> &T {
// SAFETY: `repr(transparent)` ensures that `NonZero<T>` has same layout as `T`
unsafe { &*(ptr::from_ref(self).cast::<T>()) }
}

/// Implementation of `TryFrom<&T> for &NonZero<T>`.
#[must_use]
#[inline]
fn from_ref(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`.
let opt_n = unsafe { &*(ptr::from_ref(n).cast::<Option<Self>>()) };

opt_n.as_ref()
}

/// Implementation of `TryFrom<&[T]> for &[NonZero<T>]`.
#[must_use]
#[inline]
fn from_slice(n: &[T]) -> Option<&[Self]> {
if n.iter().all(|x| NonZero::new(*x).is_some()) {
// SAFETY: We explicitly checked that all elements are nonzero, and because of `repr(transparent)`
// the layout remains unchanged
Some(unsafe { &*(slice::from_raw_parts(n.as_ptr().cast::<NonZero<T>>(), n.len())) })
} else {
None
}
}

/// Implementation of `TryFrom<[T; N]> for [NonZero<T>; N]`.
#[must_use]
#[inline]
fn from_array<const N: usize>(n: [T; N]) -> Option<[Self; N]> {
n.try_map(NonZero::new)
}

/// Returns the contained value as a primitive type.
#[stable(feature = "nonzero", since = "1.28.0")]
#[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")]
Expand All @@ -441,6 +551,31 @@ where
unsafe { intrinsics::transmute_unchecked(self) }
}
}
impl<T> [NonZero<T>]
where
T: ZeroablePrimitive,
{
/// Implementation of `From<&[NonZero<T>]> for &[T]`.
#[must_use]
#[inline]
fn as_zeroable(&self) -> &[T] {
// SAFETY: `repr(transparent)` ensures that `NonZero<T>` has same layout as `T`, and thus
// `[NonZero<T>]` has same layout as `[T]`
unsafe { &*(slice::from_raw_parts(self.as_ptr().cast::<T>(), self.len())) }
}
}

impl<T, const N: usize> [NonZero<T>; N]
where
T: ZeroablePrimitive,
{
/// Implementation of `From<[NonZero<T>; N]> for [T; N]`.
#[must_use]
#[inline]
fn into_zeroable(self) -> [T; N] {
self.map(NonZero::get)
}
}

macro_rules! nonzero_integer {
(
Expand Down

0 comments on commit 526396f

Please sign in to comment.