Skip to content

Commit

Permalink
Auto merge of #121454 - reitermarkus:generic-nonzero-library, r=dtolnay
Browse files Browse the repository at this point in the history
Use generic `NonZero` everywhere in `library`.

Tracking issue: #120257

Use generic `NonZero` everywhere (except stable examples).

r? `@dtolnay`
  • Loading branch information
bors committed Feb 23, 2024
2 parents 52cea08 + b74d8db commit b6a23b8
Show file tree
Hide file tree
Showing 18 changed files with 128 additions and 142 deletions.
18 changes: 9 additions & 9 deletions library/alloc/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use core::borrow::Borrow;
use core::ffi::{c_char, CStr};
use core::fmt;
use core::mem;
use core::num::NonZeroU8;
use core::num::NonZero;
use core::ops;
use core::ptr;
use core::slice;
Expand Down Expand Up @@ -795,22 +795,22 @@ impl From<Box<CStr>> for CString {
}

#[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")]
impl From<Vec<NonZeroU8>> for CString {
/// Converts a <code>[Vec]<[NonZeroU8]></code> into a [`CString`] without
impl From<Vec<NonZero<u8>>> for CString {
/// Converts a <code>[Vec]<[NonZero]<[u8]>></code> into a [`CString`] without
/// copying nor checking for inner nul bytes.
#[inline]
fn from(v: Vec<NonZeroU8>) -> CString {
fn from(v: Vec<NonZero<u8>>) -> CString {
unsafe {
// Transmute `Vec<NonZeroU8>` to `Vec<u8>`.
// Transmute `Vec<NonZero<u8>>` to `Vec<u8>`.
let v: Vec<u8> = {
// SAFETY:
// - transmuting between `NonZeroU8` and `u8` is sound;
// - `alloc::Layout<NonZeroU8> == alloc::Layout<u8>`.
let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v);
// - transmuting between `NonZero<u8>` and `u8` is sound;
// - `alloc::Layout<NonZero<u8>> == alloc::Layout<u8>`.
let (ptr, len, cap): (*mut NonZero<u8>, _, _) = Vec::into_raw_parts(v);
Vec::from_raw_parts(ptr.cast::<u8>(), len, cap)
};
// SAFETY: `v` cannot contain nul bytes, given the type-level
// invariant of `NonZeroU8`.
// invariant of `NonZero<u8>`.
Self::_from_vec_unchecked(v)
}
}
Expand Down
51 changes: 19 additions & 32 deletions library/alloc/src/vec/is_zero.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::num::{Saturating, Wrapping};
use core::num::{NonZero, Saturating, Wrapping};

use crate::boxed::Box;

Expand Down Expand Up @@ -69,7 +69,7 @@ unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
}

// This is recursive macro.
macro_rules! impl_for_tuples {
macro_rules! impl_is_zero_tuples {
// Stopper
() => {
// No use for implementing for empty tuple because it is ZST.
Expand All @@ -88,11 +88,11 @@ macro_rules! impl_for_tuples {
}
}

impl_for_tuples!($($rest),*);
impl_is_zero_tuples!($($rest),*);
}
}

impl_for_tuples!(A, B, C, D, E, F, G, H);
impl_is_zero_tuples!(A, B, C, D, E, F, G, H);

// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
// For fat pointers, the bytes that would be the pointer metadata in the `Some`
Expand All @@ -115,16 +115,15 @@ unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
}
}

// `Option<num::NonZeroU32>` and similar have a representation guarantee that
// `Option<NonZero<u32>>` and similar have a representation guarantee that
// they're the same size as the corresponding `u32` type, as well as a guarantee
// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
// that transmuting between `NonZero<u32>` and `Option<NonZero<u32>>` works.
// While the documentation officially makes it UB to transmute from `None`,
// we're the standard library so we can make extra inferences, and we know that
// the only niche available to represent `None` is the one that's all zeros.

macro_rules! impl_is_zero_option_of_nonzero {
($($t:ident,)+) => {$(
unsafe impl IsZero for Option<core::num::$t> {
macro_rules! impl_is_zero_option_of_nonzero_int {
($($t:ty),+ $(,)?) => {$(
unsafe impl IsZero for Option<NonZero<$t>> {
#[inline]
fn is_zero(&self) -> bool {
self.is_none()
Expand All @@ -133,23 +132,10 @@ macro_rules! impl_is_zero_option_of_nonzero {
)+};
}

impl_is_zero_option_of_nonzero!(
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroI128,
NonZeroUsize,
NonZeroIsize,
);

macro_rules! impl_is_zero_option_of_num {
($($t:ty,)+) => {$(
impl_is_zero_option_of_nonzero_int!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);

macro_rules! impl_is_zero_option_of_int {
($($t:ty),+ $(,)?) => {$(
unsafe impl IsZero for Option<$t> {
#[inline]
fn is_zero(&self) -> bool {
Expand All @@ -163,7 +149,7 @@ macro_rules! impl_is_zero_option_of_num {
)+};
}

impl_is_zero_option_of_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize,);
impl_is_zero_option_of_int!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);

unsafe impl<T: IsZero> IsZero for Wrapping<T> {
#[inline]
Expand All @@ -179,8 +165,8 @@ unsafe impl<T: IsZero> IsZero for Saturating<T> {
}
}

macro_rules! impl_for_optional_bool {
($($t:ty,)+) => {$(
macro_rules! impl_is_zero_option_of_bool {
($($t:ty),+ $(,)?) => {$(
unsafe impl IsZero for $t {
#[inline]
fn is_zero(&self) -> bool {
Expand All @@ -194,9 +180,10 @@ macro_rules! impl_for_optional_bool {
}
)+};
}
impl_for_optional_bool! {

impl_is_zero_option_of_bool! {
Option<bool>,
Option<Option<bool>>,
Option<Option<Option<bool>>>,
// Could go further, but not worth the metadata overhead
// Could go further, but not worth the metadata overhead.
}
10 changes: 5 additions & 5 deletions library/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ impl<T, const N: usize> [T; N] {
/// # Examples
///
/// ```
/// #![feature(array_try_map)]
/// #![feature(array_try_map, generic_nonzero)]
/// let a = ["1", "2", "3"];
/// let b = a.try_map(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
/// assert_eq!(b, [2, 3, 4]);
Expand All @@ -520,12 +520,12 @@ impl<T, const N: usize> [T; N] {
/// let b = a.try_map(|v| v.parse::<u32>());
/// assert!(b.is_err());
///
/// use std::num::NonZeroU32;
/// use std::num::NonZero;
/// let z = [1, 2, 0, 3, 4];
/// assert_eq!(z.try_map(NonZeroU32::new), None);
/// assert_eq!(z.try_map(NonZero::new), None);
/// let a = [1, 2, 3];
/// let b = a.try_map(NonZeroU32::new);
/// let c = b.map(|x| x.map(NonZeroU32::get));
/// let b = a.try_map(NonZero::new);
/// let c = b.map(|x| x.map(NonZero::get));
/// assert_eq!(c, Some(a));
/// ```
#[unstable(feature = "array_try_map", issue = "79711")]
Expand Down
51 changes: 25 additions & 26 deletions library/core/src/cmp/bytewise.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
use crate::num::NonZero;

/// Types where `==` & `!=` are equivalent to comparing their underlying bytes.
///
Expand Down Expand Up @@ -36,37 +35,37 @@ is_bytewise_comparable!(bool, char, super::Ordering);
// SAFETY: Similarly, the `NonZero` type has a niche, but no undef and no pointers,
// and they compare like their underlying numeric type.
is_bytewise_comparable!(
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroUsize,
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroI128,
NonZeroIsize,
NonZero<u8>,
NonZero<u16>,
NonZero<u32>,
NonZero<u64>,
NonZero<u128>,
NonZero<usize>,
NonZero<i8>,
NonZero<i16>,
NonZero<i32>,
NonZero<i64>,
NonZero<i128>,
NonZero<isize>,
);

// SAFETY: The `NonZero` type has the "null" optimization guaranteed, and thus
// are also safe to equality-compare bitwise inside an `Option`.
// The way `PartialOrd` is defined for `Option` means that this wouldn't work
// for `<` or `>` on the signed types, but since we only do `==` it's fine.
is_bytewise_comparable!(
Option<NonZeroU8>,
Option<NonZeroU16>,
Option<NonZeroU32>,
Option<NonZeroU64>,
Option<NonZeroU128>,
Option<NonZeroUsize>,
Option<NonZeroI8>,
Option<NonZeroI16>,
Option<NonZeroI32>,
Option<NonZeroI64>,
Option<NonZeroI128>,
Option<NonZeroIsize>,
Option<NonZero<u8>>,
Option<NonZero<u16>>,
Option<NonZero<u32>>,
Option<NonZero<u64>>,
Option<NonZero<u128>>,
Option<NonZero<usize>>,
Option<NonZero<i8>>,
Option<NonZero<i16>>,
Option<NonZero<i32>>,
Option<NonZero<i64>>,
Option<NonZero<i128>>,
Option<NonZero<isize>>,
);

macro_rules! is_bytewise_comparable_array_length {
Expand Down
8 changes: 4 additions & 4 deletions library/core/src/iter/traits/double_ended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub trait DoubleEndedIterator: Iterator {
/// to `n` times until [`None`] is encountered.
///
/// `advance_back_by(n)` will return `Ok(())` if the iterator successfully advances by
/// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered, where `k`
/// `n` elements, or a `Err(NonZero<usize>)` with value `k` if [`None`] is encountered, where `k`
/// is remaining number of steps that could not be advanced because the iterator ran out.
/// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
/// Otherwise, `k` is always less than `n`.
Expand All @@ -118,16 +118,16 @@ pub trait DoubleEndedIterator: Iterator {
/// Basic usage:
///
/// ```
/// #![feature(iter_advance_by)]
/// use std::num::NonZeroUsize;
/// #![feature(generic_nonzero, iter_advance_by)]
/// use std::num::NonZero;
///
/// let a = [3, 4, 5, 6];
/// let mut iter = a.iter();
///
/// assert_eq!(iter.advance_back_by(2), Ok(()));
/// assert_eq!(iter.next_back(), Some(&4));
/// assert_eq!(iter.advance_back_by(0), Ok(()));
/// assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&3` was skipped
/// assert_eq!(iter.advance_back_by(100), Err(NonZero::new(99).unwrap())); // only `&3` was skipped
/// ```
///
/// [`Ok(())`]: Ok
Expand Down
23 changes: 12 additions & 11 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ pub trait Iterator {
/// times until [`None`] is encountered.
///
/// `advance_by(n)` will return `Ok(())` if the iterator successfully advances by
/// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered,
/// `n` elements, or a `Err(NonZero<usize>)` with value `k` if [`None`] is encountered,
/// where `k` is remaining number of steps that could not be advanced because the iterator ran out.
/// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
/// Otherwise, `k` is always less than `n`.
Expand All @@ -319,16 +319,16 @@ pub trait Iterator {
/// # Examples
///
/// ```
/// #![feature(iter_advance_by)]
/// use std::num::NonZeroUsize;
/// #![feature(generic_nonzero, iter_advance_by)]
/// use std::num::NonZero;
///
/// let a = [1, 2, 3, 4];
/// let mut iter = a.iter();
///
/// assert_eq!(iter.advance_by(2), Ok(()));
/// assert_eq!(iter.next(), Some(&3));
/// assert_eq!(iter.advance_by(0), Ok(()));
/// assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&4` was skipped
/// assert_eq!(iter.advance_by(100), Err(NonZero::new(99).unwrap())); // only `&4` was skipped
/// ```
#[inline]
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
Expand Down Expand Up @@ -2967,17 +2967,18 @@ pub trait Iterator {
/// assert!(result.is_err());
/// ```
///
/// This also supports other types which implement `Try`, not just `Result`.
/// This also supports other types which implement [`Try`], not just [`Result`].
///
/// ```
/// #![feature(try_find)]
/// #![feature(generic_nonzero, try_find)]
/// use std::num::NonZero;
///
/// use std::num::NonZeroU32;
/// let a = [3, 5, 7, 4, 9, 0, 11];
/// let result = a.iter().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
/// let a = [3, 5, 7, 4, 9, 0, 11u32];
/// let result = a.iter().try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two()));
/// assert_eq!(result, Some(Some(&4)));
/// let result = a.iter().take(3).try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
/// let result = a.iter().take(3).try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two()));
/// assert_eq!(result, Some(None));
/// let result = a.iter().rev().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
/// let result = a.iter().rev().try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two()));
/// assert_eq!(result, None);
/// ```
#[inline]
Expand Down
16 changes: 7 additions & 9 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ mod private {

/// A marker trait for primitive types which can be zero.
///
/// This is an implementation detail for [`NonZero<T>`](NonZero) which may disappear or be replaced at any time.
/// This is an implementation detail for <code>[NonZero]\<T></code> which may disappear or be replaced at any time.
#[unstable(
feature = "nonzero_internals",
reason = "implementation detail which may disappear or be replaced at any time",
Expand Down Expand Up @@ -507,18 +507,16 @@ macro_rules! nonzero_integer {
/// Basic usage:
///
/// ```
/// #![feature(non_zero_count_ones)]
/// #![feature(generic_nonzero, non_zero_count_ones)]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
/// # use std::num::*;
/// #
/// let one = NonZeroU32::new(1)?;
/// let three = NonZeroU32::new(3)?;
#[doc = concat!("let a = ", stringify!($Ty), "::new(0b100_0000)?;")]
#[doc = concat!("let b = ", stringify!($Ty), "::new(0b100_0011)?;")]
#[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b100_0000)?;")]
#[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b100_0011)?;")]
///
/// assert_eq!(a.count_ones(), one);
/// assert_eq!(b.count_ones(), three);
/// assert_eq!(a.count_ones(), NonZero::new(1)?);
/// assert_eq!(b.count_ones(), NonZero::new(3)?);
/// # Some(())
/// # }
/// ```
Expand All @@ -530,7 +528,7 @@ macro_rules! nonzero_integer {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
pub const fn count_ones(self) -> NonZeroU32 {
pub const fn count_ones(self) -> NonZero<u32> {
// SAFETY:
// `self` is non-zero, which means it has at least one bit set, which means
// that the result of `count_ones` is non-zero.
Expand Down
Loading

0 comments on commit b6a23b8

Please sign in to comment.