Skip to content

Commit aba3806

Browse files
committed
Additional NonZero conversions
1 parent dfbfbf7 commit aba3806

2 files changed

Lines changed: 160 additions & 4 deletions

File tree

library/core/src/num/nonzero.rs

Lines changed: 158 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
//! Definitions of integer that is known not to equal zero.
22
3-
use super::{IntErrorKind, ParseIntError};
3+
use super::{IntErrorKind, ParseIntError, TryFromIntError};
44
use crate::clone::{TrivialClone, UseCloned};
55
use crate::cmp::Ordering;
66
use crate::hash::{Hash, Hasher};
77
use crate::marker::{Destruct, Freeze, StructuralPartialEq};
88
use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign};
99
use crate::panic::{RefUnwindSafe, UnwindSafe};
1010
use crate::str::FromStr;
11-
use crate::{fmt, intrinsics, ptr, ub_checks};
11+
use crate::{fmt, intrinsics, ptr, slice, ub_checks};
1212

1313
/// A marker trait for primitive types which can be zero.
1414
///
@@ -318,6 +318,98 @@ where
318318
}
319319
}
320320

321+
#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
322+
impl<'a, T> From<&'a NonZero<T>> for &'a T
323+
where
324+
T: ZeroablePrimitive,
325+
{
326+
#[inline]
327+
fn from(nonzero: &'a NonZero<T>) -> &'a T {
328+
nonzero.as_ref()
329+
}
330+
}
331+
332+
#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
333+
impl<'a, T> From<&'a [NonZero<T>]> for &'a [T]
334+
where
335+
T: ZeroablePrimitive,
336+
{
337+
#[inline]
338+
fn from(nonzero: &'a [NonZero<T>]) -> &'a [T] {
339+
nonzero.as_zeroable()
340+
}
341+
}
342+
343+
#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
344+
impl<T, const N: usize> From<[NonZero<T>; N]> for [T; N]
345+
where
346+
T: ZeroablePrimitive,
347+
{
348+
#[inline]
349+
fn from(nonzero: [NonZero<T>; N]) -> [T; N] {
350+
nonzero.into_zeroable()
351+
}
352+
}
353+
354+
// FIXME: can't detect that ZeroablePrimitive is a sealed trait
355+
macro_rules! impl_ref_try_from {
356+
($($t:ty),* $(,)?) => {
357+
$(
358+
#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
359+
impl<'a> TryFrom<&'a $t> for &'a NonZero<$t> {
360+
type Error = TryFromIntError;
361+
362+
#[inline]
363+
fn try_from(zeroable: &'a $t) -> Result<&'a NonZero<$t>, TryFromIntError> {
364+
NonZero::from_ref(zeroable).ok_or(TryFromIntError(()))
365+
}
366+
}
367+
)*
368+
}
369+
}
370+
371+
impl_ref_try_from! {
372+
u8,
373+
u16,
374+
u32,
375+
u64,
376+
u128,
377+
usize,
378+
i8,
379+
i16,
380+
i32,
381+
i64,
382+
i128,
383+
isize,
384+
char,
385+
}
386+
387+
#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
388+
impl<'a, T> TryFrom<&'a [T]> for &'a [NonZero<T>]
389+
where
390+
T: ZeroablePrimitive,
391+
{
392+
type Error = TryFromIntError;
393+
394+
#[inline]
395+
fn try_from(zeroable: &'a [T]) -> Result<&'a [NonZero<T>], TryFromIntError> {
396+
NonZero::from_slice(zeroable).ok_or(TryFromIntError(()))
397+
}
398+
}
399+
400+
#[stable(feature = "more_from_nonzero", since = "CURRENT_RUSTC_VERSION")]
401+
impl<T, const N: usize> TryFrom<[T; N]> for [NonZero<T>; N]
402+
where
403+
T: ZeroablePrimitive,
404+
{
405+
type Error = TryFromIntError;
406+
407+
#[inline]
408+
fn try_from(zeroable: [T; N]) -> Result<[NonZero<T>; N], TryFromIntError> {
409+
NonZero::from_array(zeroable).ok_or(TryFromIntError(()))
410+
}
411+
}
412+
321413
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
322414
#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
323415
impl<T> const BitOr for NonZero<T>
@@ -473,6 +565,45 @@ where
473565
}
474566
}
475567

568+
/// Implementation of `From<&NonZero<T>> for &T`.
569+
#[must_use]
570+
#[inline]
571+
fn as_ref(&self) -> &T {
572+
// SAFETY: `repr(transparent)` ensures that `NonZero<T>` has same layout as `T`
573+
unsafe { &*(ptr::from_ref(self).cast::<T>()) }
574+
}
575+
576+
/// Implementation of `TryFrom<&T> for &NonZero<T>`.
577+
#[must_use]
578+
#[inline]
579+
fn from_ref(n: &T) -> Option<&Self> {
580+
// SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
581+
// the same layout and size as `T`, with `0` representing `None`.
582+
let opt_n = unsafe { &*(ptr::from_ref(n).cast::<Option<Self>>()) };
583+
584+
opt_n.as_ref()
585+
}
586+
587+
/// Implementation of `TryFrom<&[T]> for &[NonZero<T>]`.
588+
#[must_use]
589+
#[inline]
590+
fn from_slice(n: &[T]) -> Option<&[Self]> {
591+
if n.iter().all(|x| NonZero::new(*x).is_some()) {
592+
// SAFETY: We explicitly checked that all elements are nonzero, and because of `repr(transparent)`
593+
// the layout remains unchanged
594+
Some(unsafe { &*(slice::from_raw_parts(n.as_ptr().cast::<NonZero<T>>(), n.len())) })
595+
} else {
596+
None
597+
}
598+
}
599+
600+
/// Implementation of `TryFrom<[T; N]> for [NonZero<T>; N]`.
601+
#[must_use]
602+
#[inline]
603+
fn from_array<const N: usize>(n: [T; N]) -> Option<[Self; N]> {
604+
n.try_map(NonZero::new)
605+
}
606+
476607
/// Returns the contained value as a primitive type.
477608
#[stable(feature = "nonzero", since = "1.28.0")]
478609
#[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")]
@@ -499,6 +630,31 @@ where
499630
unsafe { intrinsics::transmute_unchecked(self) }
500631
}
501632
}
633+
impl<T> [NonZero<T>]
634+
where
635+
T: ZeroablePrimitive,
636+
{
637+
/// Implementation of `From<&[NonZero<T>]> for &[T]`.
638+
#[must_use]
639+
#[inline]
640+
fn as_zeroable(&self) -> &[T] {
641+
// SAFETY: `repr(transparent)` ensures that `NonZero<T>` has same layout as `T`, and thus
642+
// `[NonZero<T>]` has same layout as `[T]`
643+
unsafe { &*(slice::from_raw_parts(self.as_ptr().cast::<T>(), self.len())) }
644+
}
645+
}
646+
647+
impl<T, const N: usize> [NonZero<T>; N]
648+
where
649+
T: ZeroablePrimitive,
650+
{
651+
/// Implementation of `From<[NonZero<T>; N]> for [T; N]`.
652+
#[must_use]
653+
#[inline]
654+
fn into_zeroable(self) -> [T; N] {
655+
self.map(NonZero::get)
656+
}
657+
}
502658

503659
macro_rules! nonzero_integer {
504660
(

tests/ui/suggestions/issue-71394-no-from-impl.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ LL | let _: &[i8] = data.into();
55
| ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`
66
|
77
= help: the following other types implement trait `From<T>`:
8+
`&[T]` implements `From<&[NonZero<T>]>`
89
`[T; 1]` implements `From<(T,)>`
910
`[T; 2]` implements `From<(T, T)>`
1011
`[T; 3]` implements `From<(T, T, T)>`
1112
`[T; 4]` implements `From<(T, T, T, T)>`
1213
`[T; 5]` implements `From<(T, T, T, T, T)>`
1314
`[T; 6]` implements `From<(T, T, T, T, T, T)>`
1415
`[T; 7]` implements `From<(T, T, T, T, T, T, T)>`
15-
`[T; 8]` implements `From<(T, T, T, T, T, T, T, T)>`
16-
and 7 others
16+
and 9 others
1717
= note: required for `&[u8]` to implement `Into<&[i8]>`
1818

1919
error: aborting due to 1 previous error

0 commit comments

Comments
 (0)