From 089858a82c6cfa9729a48d2b38a69f1b4e231299 Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 12 Aug 2024 22:24:51 -0400 Subject: [PATCH] Additional NonZero conversions --- library/core/src/num/nonzero.rs | 163 +++++++++++++++++- .../issue-71394-no-from-impl.stderr | 2 +- 2 files changed, 162 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index f52438e4e62e0..8bfcbf213548c 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 super::{IntErrorKind, ParseIntError}; +use super::{IntErrorKind, ParseIntError, TryFromIntError}; use crate::clone::{TrivialClone, UseCloned}; use crate::cmp::Ordering; use crate::hash::{Hash, Hasher}; @@ -8,7 +8,7 @@ use crate::marker::{Destruct, 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, intrinsics, ptr, slice, ub_checks}; /// A marker trait for primitive types which can be zero. /// @@ -318,6 +318,114 @@ where } } +#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T> From<&'a NonZero> for &'a T +where + T: ZeroablePrimitive, +{ + #[inline] + fn from(nonzero: &'a NonZero) -> &'a T { + nonzero.as_ref() + } +} + +// FIXME: see library/std/tests/slice-from-array-issue-113238.rs +/* +#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T> From<&'a [NonZero]> for &'a [T] +where + T: ZeroablePrimitive, +{ + #[inline] + fn from(nonzero: &'a [NonZero]) -> &'a [T] { + nonzero.as_zeroable() + } +} +impl [NonZero] +where + T: ZeroablePrimitive, +{ + /// Implementation of `From<&[NonZero]> for &[T]`. + #[must_use] + #[inline] + fn as_zeroable(&self) -> &[T] { + // SAFETY: `repr(transparent)` ensures that `NonZero` has same layout as `T`, and thus + // `[NonZero]` has same layout as `[T]` + unsafe { &*(slice::from_raw_parts(self.as_ptr().cast::(), self.len())) } + } +} +*/ + +#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")] +impl From<[NonZero; N]> for [T; N] +where + T: ZeroablePrimitive, +{ + #[inline] + fn from(nonzero: [NonZero; N]) -> [T; N] { + nonzero.into_zeroable() + } +} + +// FIXME: can't detect that ZeroablePrimitive is a sealed trait +macro_rules! impl_ref_try_from { + ($($t:ty),* $(,)?) => { + $( + #[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")] + impl<'a> TryFrom<&'a $t> for &'a NonZero<$t> { + type Error = TryFromIntError; + + #[inline] + fn try_from(zeroable: &'a $t) -> Result<&'a NonZero<$t>, TryFromIntError> { + NonZero::from_ref(zeroable).ok_or(TryFromIntError(())) + } + } + )* + } +} + +impl_ref_try_from! { + u8, + u16, + u32, + u64, + u128, + usize, + i8, + i16, + i32, + i64, + i128, + isize, + char, +} + +#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T> TryFrom<&'a [T]> for &'a [NonZero] +where + T: ZeroablePrimitive, +{ + type Error = TryFromIntError; + + #[inline] + fn try_from(zeroable: &'a [T]) -> Result<&'a [NonZero], TryFromIntError> { + NonZero::from_slice(zeroable).ok_or(TryFromIntError(())) + } +} + +#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")] +impl TryFrom<[T; N]> for [NonZero; N] +where + T: ZeroablePrimitive, +{ + type Error = TryFromIntError; + + #[inline] + fn try_from(zeroable: [T; N]) -> Result<[NonZero; N], TryFromIntError> { + NonZero::from_array(zeroable).ok_or(TryFromIntError(())) + } +} + #[stable(feature = "nonzero_bitor", since = "1.45.0")] #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const BitOr for NonZero @@ -473,6 +581,45 @@ where } } + /// Implementation of `From<&NonZero> for &T`. + #[must_use] + #[inline] + fn as_ref(&self) -> &T { + // SAFETY: `repr(transparent)` ensures that `NonZero` has same layout as `T` + unsafe { &*(ptr::from_ref(self).cast::()) } + } + + /// Implementation of `TryFrom<&T> for &NonZero`. + #[must_use] + #[inline] + fn from_ref(n: &T) -> Option<&Self> { + // SAFETY: Memory layout optimization guarantees that `Option>` has + // the same layout and size as `T`, with `0` representing `None`. + let opt_n = unsafe { &*(ptr::from_ref(n).cast::>()) }; + + opt_n.as_ref() + } + + /// Implementation of `TryFrom<&[T]> for &[NonZero]`. + #[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::>(), n.len())) }) + } else { + None + } + } + + /// Implementation of `TryFrom<[T; N]> for [NonZero; N]`. + #[must_use] + #[inline] + fn from_array(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")] @@ -500,6 +647,18 @@ where } } +impl [NonZero; N] +where + T: ZeroablePrimitive, +{ + /// Implementation of `From<[NonZero; N]> for [T; N]`. + #[must_use] + #[inline] + fn into_zeroable(self) -> [T; N] { + self.map(NonZero::get) + } +} + macro_rules! nonzero_integer { ( #[$stability:meta] diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index b8a240f7f07c5..e3d01bd588a4f 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -13,7 +13,7 @@ LL | let _: &[i8] = data.into(); `[T; 6]` implements `From<(T, T, T, T, T, T)>` `[T; 7]` implements `From<(T, T, T, T, T, T, T)>` `[T; 8]` implements `From<(T, T, T, T, T, T, T, T)>` - and 7 others + and 8 others = note: required for `&[u8]` to implement `Into<&[i8]>` error: aborting due to 1 previous error